# Introduction ## Welcome to ShipAhead ShipAhead is a modern, fast, and fully customizable SaaS starter kit built to help you launch apps without wasting time on boilerplate. This guide introduces the core concepts and tech powering ShipAhead so you know what’s under the hood. ## Tech Stack ShipAhead is built with a focus on performance, flexibility, and scalability. Here’s what’s included: - **Frontend**: Nuxt 4, Vue, Tailwind CSS, Nuxt UI - **Internationalization (i18n)**: Nuxt i18n - **Analytics**: Umami, Datafast, Google Analytics - **Authentication**: Better Auth (Email/Password, Magic Link, OAuth) - **Database**: Drizzle ORM & PostgreSQL (Supabase, Neon, or any PostgreSQL connection string) - **Storage**: Cloudflare R2 or S3 via aws4fetch - **Email**: Resend & Vue Email - **Payments**: Stripe, Polar, Dodo Payments - **AI**: OpenRouter AI - **PWA**: Vite PWA - **Deployment**: Vercel, Cloudflare # Setup ## Prerequisites Make sure you have these installed: - **[Node.js](https://nodejs.org/en/download/)** – Version 22.x or higher (includes npm). - **[Git](https://git-scm.com/install/)** – For version control. - **[Cursor](https://cursor.com)** or **[VSCode](https://code.visualstudio.com/)** – For editing your code. ## Setup in 5 Minutes ### 1. Clone the Repository You have three ways to get a copy: 1. **Fork + Clone** Fork the repo on GitHub, then clone your fork: ```text \[Terminal] git clone https://github.com/your-username/shipahead-template.git your-project-name ``` 2. **Use Template** Click **Use this template** on the ShipAhead repo to create a new repository, then clone it. 3. **Direct Clone** ```text \[Terminal] git clone https://github.com/Tom-Han-Org/shipahead-template.git your-project-name cd your-project-name ``` ### 2. Install Dependencies Run this to install everything the project needs: ```text [Terminal] npm install ``` ### 3. Configure Your Project - **Environment Variables** Copy the example file and update it with your settings (database URLs, API keys, etc.): ```text \[Terminal] mv .env.example .env ``` :brOpen `.env` in a text editor and fill in your values. - **App Configuration** Customize your app name, feature toggles, and other settings in `shared/config.ts`. ### 4. Run the Development Server Start your app locally: ```text [Terminal] npm run dev ``` Visit [](http://localhost:3000){rel=""nofollow""} – your app is live! 🎉 ## Pull Updates Keep your project in sync with the latest ShipAhead changes: ```text [Terminal] git remote add upstream https://github.com/Tom-Han-Org/shipahead-template.git git fetch upstream git merge upstream/main ``` > **Tip**: If there are merge conflicts, review and resolve them manually. # Database ## Tools - **[Drizzle ORM](https://orm.drizzle.team)**: Provides a lightweight, type-safe way to interact with PostgreSQL databases. ## Setup 1. Sign up / Sign in for a PostgreSQL database at [Supabase](https://supabase.com), [Neon](https://neon.com), or another provider. 2. Copy the **Database URL / Connection String** from your provider’s dashboard (e.g., `postgres://user:password@host:port/dbname`). 3. Set environment variable: ```text \[.env] DATABASE_URL="your-postgresql-database-url" ``` 4. Generate schema migrations: ```text \[Terminal] npm run db:generate ``` 5. Apply migrations to your database: ```text \[Terminal] npm run db:migrate ``` ## Usage - **Database Connection**: The database is initialized in `server/db/init.ts` using `DATABASE_URL` and connects to tables defined in `server/db/schema/`. - **Query Data**: Use Drizzle ORM in server services, e.g., insert records. ```text \[server/service/contact.ts] import { useDatabase } from '~~/server/db/init'; import * as schema from '~~/server/db/schema'; export const contactServices = { async submit(body: { name: string; email: string; message: string }) { const db = useDatabase(); await db.insert(schema.contact).values({ id: crypto.randomUUID(), name: body.name, email: body.email, message: body.message, }); }, }; ``` - **Manage Schemas**: Update `server/db/schema/` to add or modify tables. Run `npm run db:generate` and `npm run db:migrate` after changes. - **Verify Setup**: Check your database provider’s dashboard (e.g., Supabase or Neon) to confirm tables are created. # Authentication ## Tools - **[Better Auth](https://www.better-auth.com)**: Provides secure authentication with email/password, OAuth, and magic link support. ## Setup 1. For Google OAuth, sign up at [Google Cloud Console](https://console.cloud.google.com/apis/credentials) and copy the **Client ID** and **Client Secret**. 2. Update your config: ```ts \[shared/config.ts] auth: { enablePasswordLogin: true, // Allow email/password login and registration enableEmailVerification: false, // Require email verification after signup enableMagicLink: false, // Allow passwordless login via email link oauthProviders: ['google'], // Enable Google OAuth redirectAfterSignIn: '/', // Where to redirect after successful login password: { minLength: 8, maxLength: 128, pattern: /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}$/, }, }, ``` - **Note**: Add more OAuth providers (e.g., `github`, `twitter`, `apple`) to `oauthProviders` and set corresponding environment variables (e.g., `OAUTH_GITHUB_CLIENT_ID`, `OAUTH_GITHUB_CLIENT_SECRET`). 3. Set the following environment variables: ```text \[.env] BETTER_AUTH_SECRET="your-long-random-string" OAUTH_GOOGLE_CLIENT_ID="your-google-client-id" OAUTH_GOOGLE_CLIENT_SECRET="your-google-client-secret" ``` ## Usage - **Email/Password**: Sign in, sign up, reset password, sign out - **Google OAuth**: Sign in with Google account - **Magic Link**: Sign in via email link - **Verify Setup**: Use `user` and `loggedIn` from `useAuth` composable # Payments ## Setup ### Stripe 1. Sign up at [Stripe](https://dashboard.stripe.com/register) and create an account. 2. Create a **Product**in the Stripe Dashboard. - Add pricing plans (e.g. Monthly $10, Yearly $60). - Copy the **Price IDs** (they look like `price_xxx`). 3. Copy your **Secret Key** and **Webhook Secret** from the Stripe Dashboard (Developers > API Keys and Webhooks). 4. Set the following environment variables: ```text \[.env] STRIPE_SECRET_KEY="your-stripe-secret-key" STRIPE_WEBHOOK_SECRET="your-stripe-webhook-secret" ``` 5. Update pricing plans in your config: ```ts \[shared/config.ts] pricing: { paymentProvider: enums.paymentProvider.stripe, // Set paymentProvider Stripe successUrlPath: '/payment-success', // Redirect after successful payment failedUrlPath: '/payment-failed', // Redirect after failed payment plans: { pro: { enable: true, // Is show Pro Plan key: 'pro', monthly: { key: 'pro-monthly', priceId: 'price_monthly', // Set Stripe Price ID for monthly subscription mode: 'subscription', // Payment is subscription }, yearly: { key: 'pro-yearly', priceId: 'price_yearly', // Set Stripe Price ID for yearly subscription mode: 'subscription', // Payment is subscription }, }, lifetime: { enable: true, // Is show Lifetime Plan key: 'lifetime', priceId: 'price_lifetime', // Set Stripe Price ID for one-time payment promoCodeId: '', // Optional - Set Stripe Promo ID for any promo/coupon to discount mode: 'payment', // Payment is one-time }, }, }, ``` 6. Set up a webhook: - **Local**: Use [Stripe CLI](https://docs.stripe.com/stripe-cli){rel=""nofollow""} ```text \[Terminal] stripe listen --forward-to localhost:3000/api/auth/stripe/webhook ``` Copy the Webhook Secret into `.env`. - **Production**: Add a webhook endpoint in Stripe Dashboard pointing to: ```text https://your-site.com/api/auth/stripe/webhook ``` Select events like `checkout.session.completed`, `customer.subscription.created`, `customer.subscription.updated`, and `customer.subscription.deleted`. ### Polar 1. Sign up at [Polar](https://polar.sh) and create an account. 2. Create a **Product**in the Polar Dashboard. - Add pricing plans (e.g. Monthly $10, Yearly $60). - Copy the Product IDs (found in the product details/API settings). 3. Generate a **Personal Access Token** (or Organization Token) and configure a **Webhook** in the Polar Dashboard (Settings > Developers). 4. Set the following environment variables: ```text \[.env] POLAR_ACCESS_TOKEN="your-polar-access-token" POLAR_WEBHOOK_SECRET="your-polar-webhook-secret" ``` 5. Update pricing plans in your config: ```ts \[shared/config.ts] pricing: { paymentProvider: enums.paymentProvider.polar, // Set paymentProvider Polar successUrlPath: '/payment-success', // Redirect after successful payment failedUrlPath: '/payment-failed', // Redirect after failed payment plans: { pro: { enable: true, // Is show Pro Plan key: 'pro', monthly: { key: 'pro-monthly', priceId: 'price_monthly', // Set Polar Product ID for monthly subscription mode: 'subscription', // Payment is subscription }, yearly: { key: 'pro-yearly', priceId: 'price_yearly', // Set Polar Product ID for yearly subscription mode: 'subscription', // Payment is subscription }, }, lifetime: { enable: true, // Is show Lifetime Plan key: 'lifetime', priceId: 'price_lifetime', // Set Polar Product ID for one-time payment mode: 'payment', // Payment is one-time }, }, }, ``` 6. Set up a webhook: - **Local**: Use a tunneling service (like ngrok) or Polar's CLI if available to forward events to your local environment. Copy the Webhook Secret into `.env`. - **Production**: Add a webhook endpoint in Polar Dashboard pointing to: ```text https://your-site.com/api/auth/polar/webhooks ``` Select at least the following events like `order.created`, `subscription.created`, `subscription.updated`, `subscription.canceled`. ### Dodo Payments 1. Sign up at [Dodo Payments](https://app.dodopayments.com/login) and create an account. 2. Create a **Product**and its associated pricing plans in the Dodo Payments Dashboard. - Copy the **Product IDs** (they typically start with `pdt_`) for each unique plan/interval. 3. Copy your **API Key** and **Webhook Secret** from the Dodo Payments Dashboard (Developer > API Keys and Webhooks). 4. Set the following environment variables: ```text \[.env] DODO_PAYMENTS_API_KEY="your-dodo-api-key" DODO_PAYMENTS_WEBHOOK_SECRET="your-dodo-webhook-secret" ``` 5. Update pricing plans in your config: ```ts \[shared/config.ts] pricing: { paymentProvider: enums.paymentProvider.dodo, // Set paymentProvider Dodo successUrlPath: '/payment-success', // Redirect after successful payment failedUrlPath: '/payment-failed', // Redirect after failed payment plans: { pro: { enable: true, // Is show Pro Plan key: 'pro', monthly: { key: 'pro-monthly', priceId: 'price_monthly', // Set Dodo Product ID for monthly subscription mode: 'subscription', // Payment is subscription }, yearly: { key: 'pro-yearly', priceId: 'price_yearly', // Set Dodo Product ID for yearly subscription mode: 'subscription', // Payment is subscription }, }, lifetime: { enable: true, // Is show Lifetime Plan key: 'lifetime', priceId: 'price_lifetime', // Set Dodo Product ID for one-time payment mode: 'payment', // Payment is one-time }, }, }, ``` 6. Set up a webhook: - **Local**: Use a tunneling service (like ngrok) to expose your local development server. ```text \[terminal] # Example using ngrok to tunnel to your app's port ngrok http 3000 ``` Copy the resulting URL and add /api/payment/dodo/webhook to it for the Dodo Webhook configuration. - **Production**: Add a webhook endpoint in Dodo Payments Dashboard pointing to: ```text https://your-site.com/api/payment/dodo/webhook ``` Select at lease the following events like `payment.succeeded`, `payment.failed`, `subscription.active`, `subscription.updated`, `subscription.renewed`, `subscription.cancelled`, `subscription.on_hold`, and `subscription.failed`. ## Usage - **Handle Webhooks**: Plugin automatically updates subscription status on payment events. - **Verify Payments**: Check transactions and subscriptions in the plugin dashboard. - **Initiate Checkout**: Use the `paymentCheckout`function to start a payment. ```vue const { payment } = useAuth(); payment.paymentCheckout(appConfig.pricing.plans.lifetime.key, locale.value); ``` Users are redirected to payment's checkout page, then back to `successUrlPath` or `failedUrlPath` - **Customer Portal**: Let users manage subscriptions, invoices, and payment methods: ```vue const { payment } = useAuth(); payment.toCustomerPortal(); ``` # Admin Panel ## Setup To seed an Admin account, follow these steps: 1. Open the script `scripts/seed-admin-manual.cjs` and configure the new admin details: ```text \[scripts/seed-admin-manual.cjs] const newAdmin = { email: 'your_admin@yourdomain.com', password: 'your-secure-password', name: 'Your Admin Name', role: 'admin', } ``` 2. Run the command to create the admin: ```text \[Terminal] npm run seed:admin ``` ## Usage The Admin Panel dashboard is available at `/admin` (accessible only to users with the `admin` role). ### Dashboard - **Stats**: Displays total users, admins, members, and new signups (last 7 days). ### User Management - **List Users**: View all users with pagination and filter by name. - **Edit User Status**: Update a user’s status to **Active** or **Banned**. - **Create New User**: Add a new user by filling in name, email, role, and password (restricted to admins). # AI ## Tools - **[OpenRouter](https://openrouter.ai)** – Access multiple AI models for chat, text, and images. ## Setup 1. Sign up at [OpenRouter](https://openrouter.ai). 2. Create an **API Key** in Account → API Keys. 3. Add the environment variable: ```env.local OPENROUTER_API_KEY="your-openrouter-api-key" ``` 4. Select your default model in the config: ```ts \[shared/config.ts] ai: { model: 'openai/gpt-4o', // You can switch to any model from openrouter.ai/models }, ``` ## Usage ShipAhead includes ready-to-use AI pages so you don’t have to code: - **AI Chat** – `/app/pages/ai/chat.vue`:br A ready made chat interface powered by your configured AI model. - **AI Text Generator** – `/app/pages/ai/text.vue`:br Enter text, generate output, and see results instantly. The API prompt and user input are combined in one request. - **AI Image Generator** – `/app/pages/ai/image.vue`:br Generate images from prompts using supported models. # Customization ## Setup 1. **Logo** - Create a logo (PNG, \~50×50px recommended) - Save to: ```text public/images/logo.png ``` - Update your config: ```ts \[shared/config.ts] brandingImages: { logo: '/images/logo.png', openGraphImage: '/images/open-graph.png', }, ``` 2. **Open Graph Image (Social Preview)** - Create an OG image using [Canva](https://www.canva.com) or [OG Image Generator](https://www.og-image-generator.com/). - Recommended size: **1200×630px** - Save to: ```text public/images/open-graph.png ``` 3. **Favicon** - Generate favicon assets using [Favicon.io](https://favicon.io/favicon-converter/). - Place them in `public/images/`: - `android-chrome-512x512.png` → `pwa-icon-48x48.png` - `android-chrome-192x192.png` → `pwa-icon-192x192.png` - `android-chrome-512x512.png` → `pwa-icon-512x512.png` - `apple-touch-icon.png` - `favicon.ico` 4. **Font Family** - Choose a font and apply it globally: ```css \[app/assets/styles/main.css] @theme { --font-sans: 'Inter', sans-serif; } ``` 5. **Theme (Radius & Colors)** - Radius: ```css \[app/assets/styles/main.css] :root { --ui-radius: 0.5rem; } ``` - Colors: ```ts \[app/app.config.ts] ui: { colors: { primary: 'blue', neutral: 'neutral', }, }, ``` 6. **Icons (Icones.js)** - Browse icons at icones.js.org and use the icon name in your components: ```vue ``` ## Usage - Run `npm run dev` to preview changes - Verify logo, favicon, fonts, and theme in the browser - Use a social preview checker to confirm the OG image - **UI Components**: For customizing UI elements (buttons, cards, modals, etc.), refer to the [NuxtUI](https://nuxtui.com/docs/components/) # Storage ## Tools - [Cloudflare R2](https://www.cloudflare.com/products/r2) – simple and cost-effective storage (recommended) - [AWS S3](https://aws.amazon.com/s3) (or any S3-compatible service) – more advanced features ## Setup 1. Choose a storage provider: - [Cloudflare R2](https://www.cloudflare.com/products/r2) – recommended for simplicity and low cost - [AWS S3](https://aws.amazon.com/s3) (or compatible services like MinIO, DigitalOcean Spaces, etc.) 2. Create a bucket: - Go to your provider’s dashboard and create a new bucket (folder for files) - Copy the **credentials**: access key, secret key, bucket name, endpoint 3. Cloudflare R2 specific steps: 1. Sign up / Sign in at [Cloudflare](https://www.cloudflare.com/products/r2) 2. Create a new R2 bucket: - Pick a globally unique bucket name (e.g., `your-project-name`) - Select a region close to your target audience 3. Enable public access: Settings → Public Development URL → Enable - Save the public URL as `STORAGE_PUBLIC_URL` - Optional: Set custom domains for added security 4. Create a new API Token: - Storage & databases > R2 object storage > API Tokens > Manage, click Create User API Token - Set permissions to Object Read & Write to the bucket - Copy the Access Key ID and Secret Access Key 4. Set the following environment variables: ```text \[.env] S3_REGION="your-region" # Use "auto" for R2, or e.g. "us-east-1" for S3 S3_BUCKET="your-bucket-name" S3_ACCESS_KEY_ID="your-access-key-id" S3_SECRET_ACCESS_KEY="your-secret-access-key" S3_ENDPOINT="your-s3-endpoint" # Optional S3_PUBLIC_URL="https://cdn.yourdomain.com" # Public URL (CDN or subdomain) ``` ## Usage Storage functions are available in the File Management module in the Admin Panel. Use the `useApi` composable: - **List files**: ```text \[app/pages/admin/files.vue] const { getStorageFiles } = useApi(); const response = await getStorageFiles(); console.log('File uploaded list:', response.data.blobs); ``` - **Upload files**: ```text \[app/pages/admin/files.vue] const { uploadStorageFiles } = useApi(); const selectedFiles = ref([]); const response = await uploadStorageFiles(selectedFiles.value); console.log('File uploaded total:', response.data.success); ``` - **Download a File**: ```text \[app/pages/admin/files.vue] const { downloadStorageFile } = useApi(); const file = await downloadStorageFile('example.jpg'); ``` - **Delete a File**: ```text \[app/pages/admin/files.vue] const { deleteStorageFile } = useApi(); const response = await deleteStorageFile('example.jpg'); console.log('Deleted?', response.success); ``` - **Bulk delete files**: ```text \[app/pages/admin/files.vue] const { bulkDeleteStorageFile } = useApi(); const response = await bulkDeleteStorageFile(['example.jpg']); console.log('Deleted Total: ', response.data.success); ``` - **Access public file (CDN)**: ```text \[app/pages/admin/files.vue] const { public: pub } = useRuntimeConfig(); const imageUrl = `${pub.storagePublicUrl}/example.jpg`; console.log(imageUrl); // https://cdn.yourdomain.com/example.jpg ``` ## Best Practices - File Size Limits: Set reasonable file size limits to prevent abuse - File Type Validation: Validate file types on both client and server sides for security # Email ## Tools - **[Resend](https://resend.com)**: Handles sending transactional emails reliably. - **Cloudflare Email**: An alternative for sending transactional emails. - **[Maizzle](https://maizzle.com)**: Create responsive HTML emails with Tailwind CSS. ## Setup ### Resend 1. Sign up at [Resend](https://resend.com). 2. Go to API Keys to create an API Key. Fill in the name you like and keep other options as default. Then click add and copy the **API Key** . 3. Set environment variable: ```text \[.env] RESEND_API_KEY="your-resend-api-key" ``` 4. Go to Domains and add your sending domain (recommended: a subdomain, e.g., resend.yourdomain.com) and complete DNS verification. 5. Update your config: ```ts \[shared/config.ts] email: { provider: enums.emailProvider.resend, // Set email provider Resend senderName: "Your Name from Which App", senderEmail: "no-reply@resend.yourdomain.com", }, ``` ### Cloudflare Email 1. Set environment variables: ```text \[.env] CLOUDFLARE_ACCOUNT_ID="your-account-id" CLOUDFLARE_EMAIL_API_TOKEN="your-api-token" ``` - `CLOUDFLARE_ACCOUNT_ID`: Found in your Cloudflare dashboard URL or sidebar. - `CLOUDFLARE_EMAIL_API_TOKEN`: Created in **My Profile > API Tokens** (must have "Send Email" permission). 2. Onboard your domain in the Cloudflare dashboard: **Email Sending** → **Onboard Domain** → **Add records**. 3. Update your config: ```ts \[shared/config.ts] email: { provider: enums.emailProvider.cloudflare, // Set email provider Cloudflare senderName: "Your Name from Which App", senderEmail: "no-reply@yourdomain.com", }, ``` ## Usage - **Send Pre-Configured Emails**:br Use templates like `forgotPassword`, `magicLink`, or `verifyEmail`. Example for a password reset email: ```server/api/sendResetEmail.ts import { sendEmail } from '~~/server/services/email/send'; await sendEmail({ to: 'someone@email.com', template: 'forgotPassword', params: { name: 'Someone', resetUrl: 'https://your-site.com/reset-password?token=abc', }, locale: 'en', }); ``` - **Available Templates**: - `forgotPassword`: For password reset emails. - `magicLink`: For passwordless login links. - `verifyEmail`: For email verification links. - `accountDeletion`: For account deletion confirmation email. - `waitlistConfirmation`: For joining the waitlist email. - `waitlistNotification`: For notify waitlist is over and app is live. - **Customize Templates**:br Modify templates in `server/services/email/templates/` and create new ones by adding to `index.ts` and creating a Vue component in `email/components/`. - **Verify Emails**:br Check sent emails in your provider's dashboard (Resend or Cloudflare). # Languages ## Tools - **[Nuxt I18n](https://i18n.nuxtjs.org)** – Locale and translation management ## Setup English (`en`) is enabled by default. To add another language: 1. **Register the new locale in `shared/config.ts`**:br This tells the app that the language exists and can be used. ```ts \[shared/config.ts] i18n: { defaultLocale: 'en', locales: [ { code: 'en', language: 'en-US', file: 'en.json', name: 'English' }, { code: 'es', language: 'es-ES', file: 'es.json', name: 'Spanish' }, // New ], } ``` 2. **Create the translation file for that locale** Every key in this file should match the keys used in your app. ```json \[locales/es.json] { "pages.home.title": "Bienvenidos a ShipAhead", "common.siteTagline": "Tu Boilerplate SaaS", "common.siteDescription": "Una solución poderosa para tu proyecto." } ``` 3. **(Optional) Configure routing and language detection in `nuxt.config.ts`** Do this if you want URL prefixes (for example `/es/...`) or automatic language switching based on the user’s browser. ```ts i18n: { strategy: 'prefix_except_default', // /es/about but / for default locale detectBrowserLanguage: { useCookie: true, cookieKey: 'shipahead_language', fallbackLocale: 'en' }, langDir: 'locales' } ``` ## Usage - **Translate text**:br Use `useI18n()` and reference your translation keys. ```vue const { t } = useI18n(); console.log(t('pages.home.title')); // "Welcome to ShipAhead" (en) // "Bienvenidos a ShipAhead" (es) ``` - **Switch languages**:br Use the built-in `LocaleToggler` component so users can change language from the UI. ```vue \[index.vue] ``` :brWhen a language is selected, the site updates immediately. - **Default behavior**:br English is pre-configured. To support another language, add it in `shared/config.ts` and create a matching JSON file in `locales/`. - **Browser detection** - If enabled, the app tries to match the user’s browser language. - If no match exists, it falls back to the default locale. - **Tip**:br Keep translation keys consistent (for example `buttons.save`, `errors.required`) so they are easier to maintain across languages. # SEO ## Tools - **[Nuxt SEO](https://nuxtseo.com)**: Manages meta tags, sitemaps, robots.txt, and structured data for better search engine visibility. ## Configuration Most SEO is ready out of the box. Change these only if you need custom settings: - `app/composables/useSeo.ts` – manages meta tags, sitemap rules, and private pages - `shared/config.ts`– basic SEO settings: ```ts \[shared/config.ts] appName: 'ShipAhead', // Your site name brandingImages: { openGraphImage: '/images/open-graph.png', // Social image (1200x630px) }, privatePaths: ['/admin/**', '/profile/**'], // Pages hidden from search engines ``` ## How It Works - Page titles and descriptions come from your locale files (e.g. `locales/en.json`). - Fallbacks if missing: - `common.siteTagline` → title - `common.siteDescription` → description - Automatically generates: - **Meta tags** - titles, descriptions, Open Graph, Twitter Cards - **Sitemap** - all public pages at `/sitemap.xml` - **Robots.txt** - control indexing - **JSON.LD** - structured data for Google rich snippets ## Usage - **Automatic SEO for Pages**: Add titles and descriptions in locale files: ```locales/en.json { "pages.about.title": "About ShipAhead", "pages.about.description": "Learn more about our SaaS boilerplate.", "common.siteTagline": "Default Site Tagline", "common.siteDescription": "Default Site Description" } ``` - For `/about`, use pages.about.title and pages.about.description - Multi-language ready: add to es.json, fr.json, etc. - **Manual SEO Override**: For blogs or custom pages, use `setSeo`: ```pages/blogs/ \[slug] .vue const { setSeo } = useSeo(); const blog = // fetch blog data... setSeo({ pageTitle: blog.title, pageDescription: blog.excerpt, image: blog.imageUrl // Optional: Social sharing image }); ``` - Works with multi-language pages too - Lets you control exactly what Google and social platforms show # Blogs ## Tools - **[Nuxt Content](https://content.nuxt.com/)**: Render blog posts. ## Setup 1. **Create a markdown file**: - Go to `content/blog` and add a new markdown file - For other languages: - Define a new collection in `content.config.ts` with the appropriate `source` for that locale. - Create a folder for the locale (e.g., `content/es/blog`) and add a Markdown file inside it. 2. **Markdown Content**: ```md content/blog/my-new-post.md or content/blog/en/my-new-post.md --- title: My New Blog Post description: A guide to blogging in Your App. authors: - name: Tom Han to: https://x.com/tomhan245 avatar: src: https://cdn.shipahe.ad/tomhan.webp date: 2025-09-08 badge: label: SaaS --- ## Introduction This is the content of your blog post. ``` 3. **View and Verify the Blog**: - Go to `/blog` to see the blog list with titles, descriptions, thumbnails, and categories. - Open your new post at `/blog/my-new-post` to confirm it renders correctly. 4. **SEO & Sitemap**: - SEO is handled automatically using your content's `title` and `description`. - Sitemap generation is also automatic. - Customize further in page components if needed (see [Nuxt SEO Documentation](https://nuxtseo.com)). - Track SEO and sitemap performance in [Google Search Console](https://search.google.com/search-console). ## Folder Structure ```text content/ ├─ blog/ │ └─ my-first-blog.md └─ es/ └─ blog/ └─ my-first-blog.md ``` # Documentation ## Tools - **[Nuxt Content](https://content.nuxt.com/)**: Render documentation content. ## Setup 1. **Create a markdown file**: - Add a new Markdown file under content/docs for your default language. - For other languages: - Define a new collection in `content.config.ts` with the appropriate `source` for that locale. - Create a folder for the locale (e.g., `content/es/docs`) and add a Markdown file inside it. 2. **Markdown Content**: ```md content/docs/new-doc.md or content/docs/en/new-doc.md --- title: My New Documentation description: Step-by-step guide for this document. --- ## Introduction This is the content of your document. ``` 3. **View and Verify the Document**: - Go to `/docs` to see the blog list with titles, descriptions, thumbnails, and categories. - Open your new document at `/docs/my-new-doc` to confirm it renders correctly. ## Folder Structure ```text content/ ├─ docs/ │ ├─ 1.get-started/ │ │ ├─ .navigation.yml │ │ └─ 1.index.md │ └─ 2.essentials/ │ ├─ .navigation.yml │ └─ 1.markdown-syntax.md └─ es/ └─ docs/ ├─ 1.get-started/ │ ├─ .navigation.yml │ └─ 1.index.md └─ 2.essentials/ ├─ .navigation.yml └─ 1.markdown-syntax.md ``` # Cron Jobs ## Tools - **[cron-job.org](https://cron-job.org/en/)**: External service to schedule jobs by calling your API endpoints. ## Setup & Run Cron Jobs 1. **Set CRON\_SECRET** - Add an environment variable to secure your cron endpoints: ```text \[.env] CRON_SECRET="your-secret-key" ``` - Use any strong key you like or generate one with a password generator. 2. **Add a Cron Job** - Create a file in `/server/jobs/`, e.g., `sendReminderEmails.ts`: ```text \[server/jobs/sendReminderEmails.ts] export async function sendReminderEmails() { console.log('[CRON] Running job...'); // Add your logic (DB updates, notifications, etc.) } ``` - Register it in `server/jobs/list.ts`: ```text \[server/jobs/list.ts] import { sendReminderEmails } from './sendReminderEmails'; const JOBS: any = { sendReminderEmails }; export function getJobModules(name: string) { return JOBS[name] ?? null; } ``` 3. **Schedule the Job** - Trigger your job via the API endpoint: ```text https://your-site.com/api/cron/sendReminderEmails ``` - Create a cron-job.org task: - **URL**: same as above - **Execution schedule**: e.g., `0 8 * * *` (runs daily at 8 AM) - **HTTP Header**: ```text X-Cron-Secret: your-secret-key ``` 4. **Verify** - Check server logs for `[CRON]` messages. - Or test endpoint directly with curl: ```bash curl -H "X-Cron-Secret: your-secret-key" https://your-site.com/api/cron/sendReminderEmails ``` ## Why Use cron-job.org? - No need to install `node-cron` or run background workers. - Works with **serverless platforms** like Vercel, Netlify, or Cloudflare. - Secure with your custom `X-Cron-Secret`. - Easy to schedule and manage without touching your app’s main code. ## Example: Adding a New Job - Just create a new file in `/server/jobs/`, register it in `list.ts`, and schedule it on cron-job.org like above. - You can add unlimited jobs following the same pattern. # Error Handling ShipAhead uses a custom error page (`app/error.vue`) to display clear, user-friendly messages for errors such as: - Page not found (404) - Server error (500) The page shows the error code and a **“Back to Home”** button for easy navigation. # Analytics ## Tools - [Google Analytics](https://analytics.google.com) - [Umami](https://umami.is) - [DataFast](https://datafa.st) ## Setup ### Google Analytics 1. Sign up at [Google Analytics](https://analytics.google.com). 2. Create a new property, select "Web," and follow the setup wizard. 3. Copy the **Measurement ID** (e.g., `G-XXXXXXXXXX`) from the "Data Stream" settings. 4. Set environment variable: ```text \[.env] ANALYTICS_GA_ID="your-measurement-id" ``` 5. Enable in config: ```ts \[shared/config.ts] analytics: { enableGoogleAnalytics: true, }, ``` ### Umami 1. Sign up at [Umami](https://umami.is) or self-host. 2. Add a website in the Umami dashboard. 3. Copy the **Website ID** from the tracking code. 4. Set environment variable: ```text \[.env] ANALYTICS_UMAMI_WEBSITE_ID="your-umami-website-id" ``` 5. Enable in config: ```ts \[shared/config.ts] analytics: { enableUmamiAnalytics: true, }, ``` ### DataFast 1. Sign up at [DataFast](https://datafa.st). 2. Register your site in the dashboard. 3. Copy the **Website ID** from the site configuration. 4. Set environment variable: ```text \[.env] ANALYTICS_DATAFAST_WEBSITE_ID="your-datafast-website-id" ``` 5. Enable in config: ```ts \[shared/config.ts] analytics: { enableDatafastAnalytics: true, }, ``` ## Usage - **Page Views**: Automatically tracked for every visit. - **User Actions**: Clicks, navigation, and interactions are tracked. - **Dashboard**: Check analytics data in the provider dashboards: - [Google Analytics](https://analytics.google.com) - [Umami](https://umami.is) - [DataFast](https://datafa.st) ## Track Custom Events You can track specific actions with `$trackEvent`: ```text [vue] const { $trackEvent } = useNuxtApp(); // Example: tracking a navbar button click $trackEvent('navbar', { buttonName: 'Get ShipAhead' }); ``` # PWA ## Tools - **[Vite PWA](https://vite-pwa-org.netlify.app/frameworks/nuxt.html)**: Enables app installation, caching, and push notifications for Nuxt apps. ## Setup 1. Enable in config: ```ts \[shared/config.ts] pwa: { enable: true, }, ``` 2. Replace PWA icons in `/public/images/`with your own (recommended sizes): - `pwa-icon-48x48.png` (48x48 pixels) - `pwa-icon-192x192.png` (192x192 pixels) - `pwa-icon-512x512.png` (512x512 pixels) ## Usage - Generates a web app manifest for installing the app on devices. - Caches assets for faster load times. - Test: open site in Chrome → look for install prompt. - Install the app and verify it launches like a native app. # Customer Support ## Tools - **[Crisp](https://crisp.chat/en/)**: Live chat and ticketing for real-time user support. ## Setup ### Crisp 1. Create a Crisp Account: - Sign up at [Crisp](https://crisp.chat/en/). - Create a new website in your Crisp dashboard. - Copy the `CRISP_WEBSITE_ID` from the **Integrations** menu under the **HTML** option. 2. Set environment variable: ```text \[.env] CUSTOMER_SUPPORT_ID="YOUR_CRISP_WEBSITE_ID" ``` 3. Enable in config: ```ts \[shared/config.ts] customerSupport: { enable: true, }, ``` ## Usage - **Open chat widget** – the Crisp chat appears on your site once enabled. - **Respond to users** – reply to messages from the Crisp dashboard. - **Manage tickets** – track conversations and support requests in Crisp. # Project Structure - **`app/`**: Core application logic. - `app.vue`: Main app component, defining the root layout. - `app.config.ts`: Global app configuration, including colors and Nuxt UI component classes used across the project. - `components/`: Reusable Vue components (e.g., buttons, modals). - `composables/`: Reusable logic functions (e.g., `useSeo.ts` for SEO). - `middleware/`: Route-specific middleware (e.g., authentication checks). - `pages/`: Defines routes using file-based routing (e.g., `app/pages/about.vue` creates `/about`). - `plugins/`: Nuxt plugins for extended functionality (e.g., analytics). - `error.vue`: Custom error page, any unexpected error will go to this page. - **`layouts/`**: Custom layouts for pages (e.g., `layouts/default.vue`). - **`server/`**: API routes and middleware for server-side logic. - **`public/`**: Static assets like images, favicon, or fonts (e.g., `public/images/logo.png`). - **`shared/`**: Shared configuration files (e.g., `shared/config.ts` for app settings). - **`locales/`**: Language files for internationalization (e.g., `locales/en.json`). - **`content/`**: Markdown or CMS content used by Nuxt Content (e.g., blog posts, docs). ## Usage - **Navigate the Project**: Use the folder structure to locate files for customization (e.g., edit `app/pages/index.vue` for the homepage). - **Add Pages**: Create new `.vue` files in `app/pages/` to add routes (e.g., `app/pages/contact.vue` for `/contact`). - **Customize Components**: Modify or add components in `components/` for reusable UI elements. - **Configure Settings**: Update `shared/config.ts` for app-wide settings like SEO or branding. # Page Routes ## Setup Nuxt automatically generates routes from files in the `app/pages/` directory. You only need to customize routing when using `definePageMeta`. 1. **Add a page** - Create a `.vue` file in `app/pages/` (example: `app/pages/about.vue` creates `/about`). ```text \[app/pages/about.vue] ``` 2. **Dynamic Routes**: - Use square brackets for parameters (e.g., `app/pages/blogs/[slug].vue` creates `/blogs/my-post`). - Example: ```text \[app/pages/blogs/\[slug\\].vue] ``` 3. **Nested Routes**: - Use folders with `index.vue` (example: `app/pages/dashboard/index.vue` creates `/dashboard`). - Add child routes in the same folder (example: `app/pages/dashboard/settings.vue `→ `/dashboard/settings`). ## Usage - **Basic Routing**: Add `.vue` files to `app/pages/` to create pages automatically. - **Customizing Pages**: Use `definePageMeta` to set a layout or middleware: ```text \[app/pages/admin/index.vue] definePageMeta({ layout: 'admin', requireAuth: true, }); ``` - `layout: 'admin'`: Applies the admin layout from `layouts/admin.vue`. - `requireAuth: true`: Restricts access to authenticated users, defined in ShipAhead’s middleware. - **Dynamic Parameters**: Access values like `slug` using `useRoute()`. - **Verify Routes**: Run `npm run dev` and navigating to URL (e.g., `http://localhost:3000/about`). - **Learn More**: See Nuxt routing docs at [Nuxt Pages Documentation](https://nuxt.com/docs/guide/directory-structure/pages). # API Calls ## Setup 1. **Configure Database**: Set up your database first by following the [Database Setup Guide](https://shipahe.ad/docs/features/database). 2. **Verify useApi**: The `useApi` composable is pre-configured at `app/composables/useApi.ts`. No additional setup is needed unless adding custom API endpoints. ## Usage Use the `useApi` composable in your Nuxt components to call server APIs. Below are front-end and back-end examples: 1. **Front-End Example**: Import `useApi` and call `getAdminUserStats` with error handling and loading state: ```text \[pages/admin/stats.vue] ``` :brThis fetches admin stats, shows a loading state, and displays a toast notification (pop-up message) on error. 2. **Back-End Example**: Define a server API to handle the `getAdminUserStats` request with authentication: ```text \[server/api/admin/stats.ts] import { apiSuccess } from '~~/server/utils/apiResponse'; import { requireAuth } from '~~/server/auth'; import { getUserStats } from '~~/server/services/admin/stats'; export default defineEventHandler(async (event) => { const user = await requireAuth(event); if (user.role !== 'admin') { throw createError({ statusCode: 403, statusMessage: 'Forbidden' }); } const stats = await getUserStats(); return apiSuccess(stats); }); ``` :brThis checks if the user is an admin, fetches stats, and returns a formatted response. ## How It Works - **Client-Side**: The `useApi` composable (`app/composables/useApi.ts`) uses `$fetch` to call server APIs, handling methods like GET, POST, PUT, and DELETE. - **Server-Side**: APIs in `server/api/` (e.g., `admin/stats.ts`) use services (e.g., `server/services/admin/stats.ts`) for logic and return formatted responses with `apiSuccess`. - **Error Handling**: `useApi` returns errors for invalid requests (e.g., 403 for non-admins). Front-end code can handle errors with `try/catch` and show toast notifications. - **Authentication**: Protected APIs (e.g., admin stats) require a valid user session and role, checked via `requireAuth`. - **Database Dependency**: APIs like `getAdminUserStats` require a configured database to fetch data. # State Management ## Tools - **useSharedState**: A lightweight wrapper around Vue reactivity that lets multiple pages and components share the same state. ## Setup No extra setup is needed. Call `useSharedState()` anywhere in your components. 1. **Create shared state**: ```text \[vue] ``` 2. **Update values**: ```text \[vue] ``` 3. **Use it in your page**: ```text \[vue] ``` ## How to use - The same `sharedState` is shared across all pages and components - If one page updates it, every other page sees the change - Great for: - Loading states - User/session info - Data you don’t want to refetch on every page ### Quick way to confirm it works Open two pages in your app. Update sharedState on one page - the other page will update instantly. --- Think of `useSharedState` like a **shared notebook**: When one page writes something in it, every other page can read it right away. # Legal Pages by GPT ## Setup ### Option 1: Use the Built-in Generator (Recommended) Visit: [/privacy-policy-generator](https://shipahe.ad/privacy-policy-generator) Fill in your company details and generate a GDPR & CCPA compliant Privacy Policy instantly. You can copy or export the generated content into: - `app/pages/legal/tos.vue` - `app/pages/legal/privacy-policy.vue` ### Option 2: Manual GPT Prompt Method 1. Locate the legal page files: - `app/pages/legal/tos.vue` - `app/pages/legal/privacy-policy.vue` 2. Copy the pre-written prompt from the file. 3. Paste it into GPT. 4. Copy the generated content and update the respective files. # Overview ### Tools - **[Nuxt ESLint](https://eslint.nuxt.com)**: Checks your code for errors and enforces Nuxt/Vue standards. - **[Prettier](https://prettier.io/)**: Automatically formats your code for a consistent look. - **[simple-git-hooks](https://github.com/toplenboren/simple-git-hooks)**: Runs formatting and linting when you save changes to your project. ### Usage - **Linting**: Run `npm run lint` to check for issues in your code. - **Auto Fix Lint Errors**: Run `npm run lint-fix` to automatically fix common problems. - **Formatting**: Run `npm run format` to style your code automatically. - **Full Cleanup**: Run `npm run format:all` to lint and format your entire codebase in one go. - **Auto-Formatting**: Code is automatically linted and formatted when you commit changes. ### Configuration Files Modify these only if you need custom settings: - `eslint.config.mjs`: Sets rules for code error checking. - `.prettierignore`: Lists files to skip during formatting. - `.prettierrc`: Defines formatting styles (e.g., tabs, quotes). - `package.json` (Git Hooks): Sets up auto-formatting when saving changes. # Deployment Overview Deploy your app with **Vercel** or **Cloudflare** and launch your SaaS in minutes, without errors. ## Pre-Commit and Deployment Checklist Complete these steps before committing or deploying: - Run `npm run lint` to detect code issues - Run `npm run format` to ensure consistent code style - Test locally with `npm run dev` to verify everything works - Confirm your `.env.local` values are correct (API keys, database, auth, etc.) - Do not commit sensitive files (e.g., `.env` / `.env.local`) - Commit with a clear and meaningful message - Push your changes to your GitHub repository - Make sure environment variables are added in your hosting platform ## Where to deploy Choose one and learn more about the deployment in these different guides: ::card-group :::card --- color: primary icon: skill-icons:vercel-light title: Vercel to: https://shipahe.ad/docs/deployment/vercel --- Learn how to deploy your app to Vercel. ::: :::card --- color: primary icon: devicon:cloudflareworkers title: Cloudflare Workers to: https://shipahe.ad/docs/deployment/cloudflare --- Learn how to deploy your app to Cloudflare Workers. ::: :: # Vercel ## Setup 1. Sign up / Log in to [Vercel](https://vercel.com) and click **New Project**. 2. Import your GitHub repository. 3. Set the **Framework Preset** to **Nuxt**. 4. Add your environment variables from `.env` if required. 5. Click **Deploy** to build and publish your app. 6. Open and verify your live app using the generated Vercel URL. 7. Auto-deploy happens on every push to the main branch. 8. Check logs in Vercel if something fails during build or runtime. # Cloudflare Workers ## Setup 1. Sign up / Log in to Cloudflare. 2. Set up Hyperdrive (for database connections): - In the Cloudflare dashboard, go to **Storage & Databases → Hyperdrive**. - Click **Create Hyperdrive** and connect it to your database (e.g., Postgres, MySQL). - Once created, copy the **Hyperdrive ID**. - Run the following command in your project ```text \[Terminal] mv wrangler.example.toml wrangler.toml ``` - Set it to wrangler.toml: ```text \[wrangler.toml] [[hyperdrive]] binding = "HYPERDRIVE" id = "your-hyperdrive-id" ``` 3. Set nitro preset in environment variable: ```text \[.env] NITRO_PRESET="cloudflare_module" ``` 4. Commit changes and push to your repository. 5. Deploy via Cloudflare: - Go to **Workers & Pages → Create Application → Create Worker**. - Connect your GitHub repository. - Set the build command to: `npm run build` - Add environment variables (`.env.local` values). - Click Deploy to build and launch 6. Access and verify your live site at the Cloudflare Workers URL. 7. Auto-deploy happens on every push to the main branch. 8. Check logs in Cloudflare dashboard if something fails during build or runtime. # 7 Nuxt CI/CD tools with a battle-tested release checklist ![Ship Nuxt reliably with a CI/CD stack we use in production. Tools, example configs, and a practical release checklist for a typed Nuxt SaaS codebase.](https://shipahe.ad/images/blog/7-nuxt-ci-cd-tools-and-a-checklist-for-reliable-releases/post-411.webp){style="max-width:100%;border-radius:12px"} Shipping a Nuxt app every week without pager noise is a process problem, not a framework problem. This is the CI/CD stack and checklist we use to ship our typed Nuxt SaaS starter, Shipahe.ad, on a tight loop. It keeps builds fast, previews useful, and releases boring in the best way. ## 1. Start with a CI-friendly Nuxt starter A pipeline is only as stable as the codebase it validates. A fully typed Nuxt starter like Shipahe.ad gives CI clear targets to check: database and ORM with migrations, authentication, protected routes, an admin panel, transactional emails, payments with webhooks, S3-compatible storage, i18n, analytics, SEO helpers, cron jobs, and a landing page. Those pieces map to automated steps instead of hand-written one-offs. Because the code is typed end to end, a TypeScript check in CI catches whole classes of bugs before they hit a preview. We also design our repo with CI in mind: consistent scripts in package.json, conventional commits for readable changelogs, test fixtures for auth and billing, seed data for admin flows, and a minimal .env.example for each environment. That structure makes it simple to wire jobs and safe to onboard AI coding tools like Cursor or Claude to generate pipeline changes without breaking guardrails. ## 2. Runners and caching: make builds fast and repeatable Pick a runner that mirrors where you deploy. GitHub Actions, GitLab CI, and CircleCI are flexible and work well when you deploy to SSH targets or container platforms. If you deploy to Vercel, Netlify, or Cloudflare Pages, their native pipelines give you atomic deploys and solid previews. Use a self-hosted runner only when you need custom system packages or private networking to reach internal databases. Caching is the cheapest speed win. Cache your package manager store and the build output with keys that change only when inputs change. For Node projects we standardize on pnpm and cache against OS, Node version, and lockfile: ``` ``` For monorepos, split caches per workspace so a docs change does not bust app caches. If your host can reuse artifacts, publish the .nuxt output from CI and have deploy jobs pull it instead of rebuilding. ## 3. Make quality gates non-negotiable Gate merges on checks that reflect real user risk. We keep four lanes: - Lint and formatting: run ESLint and your formatter before anything else. Fail fast on unused exports and accidental console logs. - Type safety: run `pnpm typecheck` and treat new errors as blockers. On a typed starter like Shipahe.ad, this pays off immediately. - Unit and component tests: run in parallel with the build. Keep them deterministic with seed data and factory helpers. - Smoke-level E2E: headless Playwright is enough. Cover home, sign in, a protected page, an admin action, and one payment flow in test mode. Use a matrix when needed, but do not overspend. If production runs Node 20 on Linux, that is the lane that matters. Add branch protection so main stays deployable. Use `concurrency` to cancel in-progress jobs on rapid pushes and keep the queue clear. ## 4. Previews and environment management Every pull request should produce a preview you can click. Reviewers catch more by clicking than by reading diffs, especially for auth-gated and i18n features. Previews are only useful if they are safe and complete: - Seeded auth: provision a test user and admin in your seed script. In Nuxt, wire a CLI task like `pnpm db:seed` into the preview job. - Payments in test mode: use provider test keys and static webhook secrets for previews. Hit a health endpoint that confirms webhooks return 2xx. - Ephemeral data: point previews at an isolated database. Auto-create the schema, run migrations, and drop it on cleanup. - i18n sanity: toggle the locale switcher in E2E and confirm translated routes and SEO tags render. Manage secrets as pipeline inputs, not as .env files in the repo. In Actions or your CI of choice, scope secrets to environments and jobs. For Nuxt 3, use runtimeConfig to separate public and server values. A typical mapping looks like this: ``` ``` Keep production-only features behind flags. In Nuxt, read flags from runtimeConfig and guard routes and components. This prevents private beta features from leaking in previews or to the public site. ## 5. Plan rollouts, monitor, and communicate Small, frequent releases reduce risk. Use atomic or immutable deploys when your host supports them so rollbacks are a click, not a rebuild. For higher-risk changes, do a staged rollout: route a small percent of traffic to the new build or enable a feature flag for a cohort. Monitoring starts in CI. Fail the deploy if database migrations do not apply in staging. In production, watch error rates, webhook failures, and checkout conversion in the first hour after a release. Keep a one-command rollback documented in the repo that also handles database considerations. We keep the previous build artifact and a down migration ready for tagged releases. Write release notes that map to user value, not just technical changes. If a change affects public pages or docs, coordinate with your content workflow. For teams that care about search and how AI answers surface your updates, this is a useful read: [this SEO automation tool guide to generative engine optimization (GEO)](https://rankgoat.app/blog/what-is-generative-engine-optimization-geo-plain-english-guide){rel=""dofollow""}. It explains how automated content, technical fixes, and backlinks influence both Google rankings and AI answer boxes. ### A pre-flight checklist for reliable Nuxt releases - Build sanity: Node version pinned, dependency cache restored, build completed without warnings you plan to ignore. - Type safety: TypeScript check passes. For typed starters like Shipahe.ad, treat any new type error as a blocker. - Auth and protected pages: Login, magic link, Google sign-in, and logout flows verified in preview. Protected routes only load for authenticated users. - Admin panel: Admin dashboard loads, user management actions work, spam ban action tested with a dummy account. - Payments: One-time checkout and subscription flow tested in provider test mode. Webhooks reachable and returning 2xx. No live keys in non-production. - Emails: Password reset, welcome, and notification templates render with real data in a staging inbox. Links point to the right environment. - Database and ORM: Pending migrations applied in staging, rollback path documented. Seed scripts safe to re-run. - File uploads: S3-compatible storage keys present, test upload and secure download work. Old artifacts clean up on rollback. - i18n: Language switch works, translated routes render, and SEO tags exist for each locale where relevant. - Cron jobs: Scheduled tasks enabled in production only. Daily reports and reminders point to production services. - Analytics: Built-in analytics receiving pageviews and signups in staging and production with separate datasets. Sampling and privacy settings reviewed. - SEO: Automatic meta tags and Open Graph images render in preview. Sitemap generated and accessible. Changelog or release notes drafted for user-facing changes. - Access control: Feature flags or environment checks in place so experimental features do not leak to all users. - Rollback: Previous build still available. One command or click documented to revert, including database considerations. ### Key takeaways - Pick a runner that fits your host and security needs, then cache everything you can. - Automate linting, type checks, unit tests, and a small set of E2E smokes so main is always releasable. - Use preview deployments to validate UI, auth, payments, and i18n before merging. - Treat secrets, webhooks, and cron jobs as part of the release, not afterthoughts. - Prefer atomic deploys, keep a clear rollback, and publish notes users can trust. CI/CD is not a trophy pipeline. It is a habit. Start small, script the boring parts, and keep shipping. If you prefer to start from a Nuxt SaaS boilerplate you can buy, choose one like Shipahe.ad that already includes authentication, payments, emails, analytics, SEO tools, i18n, cron jobs, and an admin. Your pipeline then maps to real features on day one. ## Recommended resources - [this SEO automation tool guide to generative engine optimization (GEO)](https://rankgoat.app) # Nuxt Boilerplate for SaaS: What to Ship First and Why ![Use a Nuxt boilerplate to launch a SaaS fast. See the core pieces, build vs buy, a 10 day plan, and how Shipahe.ad handles auth, payments, i18n, admin, and SEO.](https://shipahe.ad/images/blog/beginners-guide-nuxt-boilerplate-saas-apps/post-513.webp){style="max-width:100%;border-radius:12px"} You do not get paid for wiring login flows, checkout, and settings. You get paid for solving a customer problem. A Nuxt boilerplate gives you a working base so you can ship the money path first and get real users in days, not months. Below is a practical take on what a Nuxt boilerplate is, the parts a SaaS actually needs, when to build vs buy, and a 10 day plan to reach a usable, payworthy first release. ## Ship faster with a Nuxt boilerplate Nuxt sits on top of Vue and gives you file based routing, server rendered pages, and a clean conventions over configuration setup. You organize pages in `/pages`, server endpoints in `/server/api`, and guard routes with middleware. SSR and API routes run on Nitro, which keeps the same code working locally and in production. A Nuxt boilerplate is a repo that turns those primitives into a ready to run app: auth flows, protected pages, checkout, admin, and the basic marketing surface. It removes weeks of glue work so you can put most of your time into one or two core features that prove value. With Shipahe.ad, that foundation is prebuilt: user authentication with email, magic links, and Google, protected routes, checkout for one time and subscriptions with swappable providers, a typed database with an ORM and migrations, S3 compatible file uploads, transactional emails, an admin panel, built in analytics, SEO helpers, scheduled jobs, AI chat and generation with switchable GPT models, a blog, and a customizable landing page. It is also tuned to play well with AI coding tools like Cursor and Claude if you use them in your workflow. ## The building blocks your SaaS actually needs ### Accounts and protected areas Users should be able to sign up, sign in, and reach private pages without friction. A solid boilerplate ships email and password, magic links, and a social provider like Google. Route middleware keeps private pages off limits to guests. Plan for password resets and session revocation from day one. ### Payments and plans Revenue depends on a checkout that works every time. You want a drop in flow for subscriptions and one time payments, trials, upgrades, downgrades, cancellations, and invoices. Webhook handling with signature verification and idempotency is non negotiable. Proration rules and trial transitions are easy to get wrong, so start with tested flows and adapt pricing, not the protocol. ### Data, files, and email Your app needs migrations, typed models, and a repeatable seed script. For uploads, prefer presigned URLs to avoid proxying large files through your server. Transactional email templates for welcome, password reset, and purchase receipts should be ready to edit. Use environment specific SMTP keys and verify domains early to avoid deliverability surprises later. ### Admin and analytics You will want to see users, plans, and events at a glance. An admin panel that lists accounts, flags spam, and lets you ban abusers saves hours. Lightweight analytics for pageviews, signups, and conversion let you find leaks without adding another tool on day one. Log key events to your admin for fast debugging. ### i18n and SEO Internationalization only works if it is part of the skeleton. A language switcher, locale files, and per locale routes make translation straightforward. On the SEO side, generate meta tags, Open Graph, and a sitemap by default so marketing pages index correctly and look right when shared. ### Automation and scheduled jobs Many SaaS workflows are time based. A scheduler for daily digests, usage resets, reminder emails, or cleanup tasks keeps you from bolting on cron later. Local development should let you run and test these jobs by hand. ### AI features and developer workflow If you are building an AI product, start with working chat, text, and image generation endpoints and usage limits. Keep model providers swappable so cost and latency experiments are cheap. Make sure the dev loop is short: type safe APIs, hot module reload, and scripts for seeding, running tests, and pushing to staging. ### Marketing surface Launch with a customizable landing page and a blog. Nuxt Content with Markdown is enough to publish updates and rank for early terms. Wire CTAs to your signup and set canonical URLs, social images, and schema. ## Build vs buy: a practical call Building everything yourself is possible, but it costs calendar time and attention you will not get back. The risky parts are not glamorous: OAuth callback edge cases, webhook retries and replay protection, subscription proration, VAT and tax settings, presigned upload security, and email deliverability. Each one can burn a week. - If your app needs a highly unusual auth flow or a novel billing model, you may need custom work. Budget the time. - If your needs are typical, start with a Nuxt boilerplate and adapt it. You keep control of your product while skipping unoriginal scaffolding. - Consistency matters. A starter with conventions, typed models, tests, and scripts reduces regressions when you iterate. The goal is not to outsource judgment. It is to remove low level plumbing so you can spend your best hours on the feature that gets someone to pay. ## A 10 day launch plan with a starter kit 1. **Day 1: run the app and secure routes.** Install, boot locally, create an account, and hit a protected page. Add a logged out route test and a logged in route test to catch regressions. 2. **Day 2: wire payments end to end.** Configure keys, create a test product and price, and run both a one time and a subscription checkout in test mode. Verify webhooks, idempotency keys, and error handling. Cancel, upgrade, and downgrade once to see proration behavior. 3. **Day 3: brand the surface.** Replace logo, colors, and typography on the landing page. Update copy blocks, FAQs, and CTAs. Set meta tags, Open Graph images, and a sitemap. Publish a first blog post that outlines the problem you solve and links to signup. 4. **Day 4: i18n baseline.** Turn on the language switch. Translate the landing page and one core screen into a second language to validate your translation workflow and routing. Store the user’s locale preference. 5. **Day 5: emails that earn trust.** Edit welcome, password reset, and receipt templates. Send test emails to real inboxes, check spam folders, and set SPF, DKIM, and DMARC. Add a footer with support links and your company details. 6. **Day 6: data and uploads.** Define the first two domain models, write migrations, and seed sample data. Configure S3 compatible storage and test presigned uploads and secure downloads from a protected page. 7. **Day 7: admin and analytics.** Add filters to the user list, a plan column, and a ban flow. Confirm that pageview and signup events show up. Log key events such as checkout completed, plan changed, and email sent so you can debug quickly. 8. **Day 8: feedback loop.** Invite a few testers. Capture qualitative input where it is easy to process. If you need structure, set up [product feedback management with Feedjolt](https://feedjolt.com) so customers can submit, vote, and you can merge duplicates and prioritize in public. Integrate Slack or issue tracking if that helps you act fast. 9. **Day 9: AI feature slice.** If you are building an AI tool, ship a thin vertical slice: one prompt, one route, usage limits, and a simple history view. Start with a default model and keep the provider swappable so you can test cost and speed later. 10. **Day 10: staging and release.** Create separate environments for local, staging, and production. Lock down env vars, rotate keys, and run smoke tests: signup, login, checkout, receipt, i18n toggle, and a protected page. Ship to production and invite the first paying users. From here, add tests around the money path, monitor failures in your admin, and iterate on the one feature that keeps people coming back. ## Key takeaways - A Nuxt boilerplate removes weeks of glue work so you can ship the money path first. - The essentials are auth, payments, data and files, emails, admin, analytics, i18n, SEO, automation, AI endpoints if needed, and a marketing surface. - Use a starter when your needs are typical and focus on your product’s core value. Build custom only where you must. - Shipahe.ad bundles the pieces most teams build anyway and lets you start at feature one. - Do less but finish: signup, checkout, one protected page, and one core feature live in 10 days is a realistic goal. A starter kit does not decide your product, but it clears the path. Pick a boilerplate that matches your needs, verify the critical flows, and put version one in front of real users this week. ## Recommended resources - [product feedback management with Feedjolt](https://feedjolt.com) # Best Nuxt admin templates for SaaS dashboards in 2026 A SaaS dashboard has to look polished, feel fast, and stay flexible as your product grows. Pick the wrong Nuxt admin template and you will spend weeks undoing opinions. Pick the right one and you can move from a Figma mock to a working, branded dashboard in days. This guide focuses on Nuxt 3 options that scale with real teams. You will see how the main template approaches compare, when a full starter kit makes more sense, what to expect on pricing and support, and the setup pitfalls that cost time if you miss them. ## How we evaluated Nuxt admin options A workable template should get you to a secure, themeable, data-rich dashboard without fighting the framework. We prioritized Nuxt-first stacks and measured them by how quickly we could ship a sortable table, a chart, and protected routes. - Framework fit. Native Nuxt 3 support, SSR compatibility, route middleware for protected areas, and predictable layouts. - Component depth. Tables, forms, charts, dialogs, toasts, and navigation primitives that cover daily admin tasks. - Design system. Themeable tokens for color, spacing, and typography with dark mode and accessible states. - Developer ergonomics. TypeScript types, sane folder structure, plugin setup, and clear examples. - Performance and a11y. Reasonable bundle size, lazy loading, semantic HTML, keyboard navigation, and focus management. - Licensing and support. Transparent terms, update cadence, and evidence of maintenance or community adoption. We built a small demo with each approach, timed the path to a sortable data table and a chart, checked Lighthouse for a baseline, and verified how easily we could adapt brand tokens and add auth-guarded routes. ## The main Nuxt admin template approaches ### Tailwind-first Nuxt admin template A Tailwind-first stack gives utility-first styling, predictable spacing, and a fast path to on-brand UI. Paired with headless components, you assemble only what you need and keep CSS overhead low. - Starter sketch. Install Tailwind in Nuxt, add a layout with a sidebar and top bar, wire dark mode with a color-mode module or a simple class toggle, and compose cards, tables, and forms from headless primitives. For charts, mount a client-only component to avoid SSR pitfalls. - Pros. Lightweight, easy to theme via tokens, integrates cleanly with Nuxt file-based routing and layouts, and is straightforward to performance-tune. - Cons. More assembly work for data-heavy widgets, and accessibility depends on the headless primitives and how you wire them. - Best for. Teams that value performance, brand control, and clean code. Great for early SaaS dashboards that will evolve quickly. ### Vuetify-based Nuxt admin template Vuetify delivers a mature Material Design system with consistent patterns out of the box. It reduces decision fatigue and accelerates dense admin screens. - Starter sketch. Install Vuetify 3, register it in a Nuxt plugin, include the styles, and use built-in layouts, navigation drawers, data tables, and form controls. Prefer server-side pagination and sorting on large tables to keep interactions snappy. - Pros. Deep component suite, sensible defaults, robust accessibility, and strong documentation for complex layouts. - Cons. Heavier bundle footprint and a Material look that takes work to fully restyle. - Best for. B2B products that want predictable UX and reliable building blocks over minimal bundle size. ### PrimeVue-based Nuxt admin template PrimeVue shines when you need advanced data components like powerful tables, trees, and filters. It is a quick route to CRUD-heavy dashboards and reporting views. - Starter sketch. Install PrimeVue and PrimeIcons, import a theme CSS in nuxt.config, register a plugin, and drop in DataTable, Dropdown, Calendar, and OverlayPanel components. Use lazy loading for tables and virtual scrolling where datasets are large. - Pros. Wide component coverage, multiple theming options, fast path to complex inputs and data navigation. - Cons. Configuration-heavy components have a learning curve, and visual style can clash if mixed with other systems. - Best for. Data-dense SaaS where the admin doubles as a light analytics or reporting surface. ### Minimal Nuxt admin shell with Composition API Sometimes the best template is a thin, predictable shell. With Nuxt layouts and the Composition API, you can stand up a secure, type-safe admin in an afternoon. - Starter sketch. Create an admin layout with a sidebar and top bar, add route middleware for auth, define a base card and table, and integrate your preferred chart and form libraries. Use a typed store for user and permissions. - Pros. Small surface area, zero lock-in, and easy to optimize. Clean mental model for senior teams. - Cons. You build most widgets yourself, which takes time for complex screens. - Best for. Experienced developers or teams with a strong in-house design system and strict brand requirements. ## Full Nuxt SaaS starter kit: Shipahe.ad When you need more than UI, a full Nuxt starter kit saves months. Shipahe.ad is a Nuxt boilerplate with an Admin Panel and a prebuilt landing page you can customize, so you launch dashboards and customer pages fast and start charging sooner. - Admin Panel. View users, manage accounts, and ban spammers with role-based controls. - User authentication. Email and password, magic links, social logins, password reset, and protected pages wired end to end. - Payments. One-time and subscription flows with customer portal patterns ready to adapt to your provider. - Internationalization. Multi-language support with an in-app language switch and translation keys organized for scale. - Transactional email. Pre-made templates for resets, welcomes, and notifications with a clean abstraction for providers. - Database. Preconfigured ORM and migrations in a fully typed codebase, including seed scripts for local dev. - File storage. S3-compatible uploads with signed access for secure delivery. - AI features. Chat, text, and image generation with switchable GPT-style models, plus hooks for AI coding tools. - Operational tooling. Built-in analytics, SEO helpers, cron jobs, and a Nuxt Content blog. - Marketing. A prebuilt, editable landing page that ships on day one. Who benefits most. Founders and small teams that want to skip wiring auth, payments, i18n, emails, analytics, and admin again. If your goal is to build and sell an AI tool or SaaS quickly, Shipahe.ad gives you the rails to move from idea to revenue without reimplementing the same infrastructure. ## Pricing, licensing, and support Templates range from free MIT stacks to commercial licenses with updates. Free lowers cost but shifts maintenance to you. Commercial licenses often include patterns and examples that compress build time and de-risk edge cases. - License scope. Check whether the license covers a single project or unlimited products. Confirm if employees and contractors are both allowed under the same seat. - Update policy. Look for clear versioning, changelogs, and migration guides. A monthly or quarterly cadence is a healthy signal. - Support expectations. Clarify whether support means docs only, an issue tracker, or email with response-time targets. Ask how long critical fixes typically take. For a Nuxt SaaS template you plan to run in production, optimize for total cost of ownership over 12 months. An option that gets you to a reliable release in weeks and stays maintainable is usually cheaper than a free template that burns time on auth, billing, and dashboards. ## Setup tips and common pitfalls - Lock framework versions. Start from the template’s recommended Nuxt and Vue versions. Minor mismatches can break SSR or devtools. - Plan auth early. Add route middleware to guard admin pages, protect server routes, and test logout flows. Do not index admin routes in robots or sitemaps. - Define design tokens first. Set colors, spacing, typography, and radii before building screens to avoid rework when brand updates land. - Tables and charts. Tree-shake chart libraries and paginate server-side. Prefer lazy components for heavy visuals to keep TTI low. - Accessibility passes. Test keyboard navigation, focus traps in dialogs, and visible focus states. Add a skip link in the layout. - i18n from day one. Use translation keys and namespaces. Avoid hardcoded copy in components. - Environment safety. Keep secrets server-side and expose only what you must via public runtime config. Never leak credentials into client bundles. - Error states. Design empty, loading, and failure states for every critical view. An admin with clear fallbacks reduces support load. - Analytics and SEO. Exclude admin from pageview tracking and sitemaps. Keep marketing pages fast with image optimization and prefetching. **Key takeaways** - Choose the approach that matches your component needs and design system, not just the prettiest demo. - Tailwind-first gives speed and control, Vuetify and PrimeVue accelerate dense UIs, and a minimal shell maximizes flexibility. - Free is fine for prototypes, but commercial support can repay itself in a single week of saved time. - Plan auth, routing, and a11y up front to avoid expensive rewrites. - When you need dashboards plus auth, payments, i18n, emails, analytics, and SEO, a full Nuxt boilerplate like Shipahe.ad is faster and safer. # The Best SaaS Stack in 2026 – Tools to Build and Launch Fast I’ve wasted more time than I’d like to admit choosing a "perfect" tech stack. You know the drill: You spend three days comparing Drizzle vs Prisma, another two days wrestling with auth libraries, and by the time you're ready to write your first feature, the excitement for the project has already started to fade. In 2026, the tech landscape is noisier than ever. But if your goal is to launch a profitable SaaS (and not just play with new frameworks), you need a stack that gets out of your way. This is the exact, no-fluff architecture I use to ship fast and scale without the headache. --- ## Why Your Choice of Tools Matters Your technical choice is the foundation of your house. If the foundation is weak, the house falls down when you try to add a second floor. Choosing the right **modern SaaS development** tools helps you: - **Move Fast:** You don't build everything from scratch. - **Scale Without Stress:** Your app handles 1,000 or 100,000 users just as easily. - **Focus on Value:** You spend your time on the features that people actually pay for. Many smart founders use a **SaaS boilerplate architecture** like [ShipAhead](https://shipahe.ad){rel=""nofollow""} to skip the boring config work and get straight to building. --- ## The Front-End: Speed and SEO ### Nuxt 4 + Vue 3 Your front-end is what your users see and feel. For 2026, **Nuxt 4** is the gold standard. It is fast, handles SEO naturally, and has a great developer experience. It makes your site feel like a local app rather than a slow website. ### Tailwind CSS Design is hard. **Tailwind CSS** makes it easy. Instead of writing messy CSS files, you use simple classes to style your app. It is the fastest way to build beautiful, responsive interfaces that work perfectly on phones and computers. --- ## The Back-End: Reliability and Data ### Database: Postgres + Drizzle ORM Data is the heart of your SaaS. **Postgres** is the most reliable database choice. It is safe, fast, and works everywhere. Pair it with **Drizzle ORM** to talk to your database. Drizzle stops you from making common mistakes and keeps your code clean. ### Node.js + Serverless You don't want to manage servers. Using **serverless** functions means you only pay for what you use. If nobody is on your site, you pay zero. When you go viral, your backend scales up automatically. --- ## Essential Infrastructure: Login and Payments ### Better Auth for Safe Logins Security is scary. Don't build your own login system. Use **Better Auth**. It handles passwords, Google logins, and session management for you. This keeps your user data safe while giving you more time to build. ### Stripe for Payments If you want to make money, use **Stripe**. It is the industry standard for **full-stack SaaS tools**. Stripe handles monthly subscriptions, tax, and one-time payments with a few lines of code. --- ## Working with AI Coding Tools In 2026, you shouldn't be writing every line of code by hand. Tools like **Cursor** and **Claude** are essential. The secret to using AI effectively is having a clean **Nuxt 4 SaaS** structure. When your code is organized, AI can understand your project and suggest fixes in seconds. This is why a standardized stack is so powerful. --- ## Deployment: Putting Your App Online ### Vercel or Cloudflare In 2026, "deploying" should take one click. **Vercel** and **Cloudflare** are the best platforms for hosting modern apps. They handle the security, caching, and global delivery of your SaaS so you don't have to hire a DevOps engineer. --- ## ShipAhead: The Shortest Path to Launch Setting all of this up manually takes weeks. [ShipAhead](https://shipahe.ad){rel=""nofollow""} gives you a professional **scalable SaaS guide** in code. It comes with: - **Pre-built Nuxt 4 & Tailwind** setup. - **Fully integrated Authentication** with Better Auth. - **Stripe payments** ready for your API key. - **Postgres & Drizzle** database configuration. It is designed for founders who want to build a business, not just a configuration file. ### How to Choose the Best Foundation? If you are still undecided, check out our comprehensive guide on the [7+ Best Nuxt Starter Kits for 2026](https://shipahe.ad/blog/top-saas-starter-kits) where we compare the top options for rapid development. --- ## Final Thoughts The **Best SaaS Tech Stack 2026** is about choosing simplicity over complexity. By using Nuxt, Postgres, and Stripe, you are setting yourself up for success. Don't wait for the "perfect" time. Pick your tools, use a starter kit, and start shipping. The world needs your idea. # How to Choose a Nuxt SaaS Boilerplate (2026 Guide) Starting a SaaS from zero is a massive energy drain. You spend the first two weeks setting up logins, wrestling with database schemas, and fighting with Stripe APIs. By the time you’re ready to build your actual product, you’re already exhausted. This is why I always use a **pre-built application scaffold** for new projects. Instead of wasting weeks on infrastructure, I can launch a working MVP in a single weekend. But not every starter kit is worth the money. Here is my framework for choosing a foundation that won't turn into a maintenance nightmare six months down the line. --- ## What are the benefits of using a pre-built application scaffold? Before you write a single line of code, you should understand why the world's most productive developers use starter kits. The **benefits of using a pre-built application scaffold** include: 1. **Tested Security:** Authentication is hard. Pre-built solutions use battle-tested libraries like Better Auth or Clerk. 2. **Integrated Payments:** Most kits come with Stripe webhooks already configured, so you can start charging users immediately. 3. **Modern Architecture:** You get a clean, scalable folder structure (like the Nuxt 4 `app/` directory) that is ready for growth. 4. **AI Compatibility:** Modern scaffolds are designed to be "AI-native," making it easy for tools like Cursor or Claude to help you code. --- ## How to Choose the Right Kit for Your Project Not all starter kits are created equal. When deciding **how to choose a pre-configured solution for web development**, consider these factors: ### 1. Technology Stack Alignment Does the kit use tools you actually want to use? In 2026, the gold standard for Nuxt is: - **Framework:** Nuxt 4 - **Database:** Postgres (with Drizzle or Prisma) - **UI:** Nuxt UI or Tailwind CSS - **Auth:** Better Auth or Auth.js ### 2. Ease of Customization Some kits are "opinionated" and hard to change. Look for a kit like **ShipAhead** that provides a clean foundation without forcing you into a specific way of building your core logic. ### 3. Documentation and Support A fast start is only possible if you don't get stuck. High-quality kits provide searchable documentation and a community or direct support line. --- ## Best options for quickly starting a new web project If you are looking for the absolute **best options for quickly starting a new web project** in 2026, here are our top recommendations: - **ShipAhead:** Best for solo founders and AI-driven development. - **supastarter:** Best for complex enterprise requirements. - **Nuxt SaaS Kit:** Best for content-heavy SaaS. --- ## Step-by-Step: From Scaffold to Launch Once you have chosen your **pre-configured solution**, the path to launch is simple: 1. **Initialize:** Clone the repository and install dependencies. 2. **Configure:** Add your API keys for Auth, Database, and Payments to your `.env` file. 3. **Customize:** Replace the placeholder branding with your own and start building your unique features. 4. **Deploy:** Connect to Vercel or Cloudflare and go live. --- ## Conclusion: Stop Configuring, Start Building The biggest mistake founders make is building for too long in private. Using a **pre-built application scaffold** lets you get your product in front of customers while the idea is still fresh. You should be spending 90% of your time talking to users and 10% coding the infrastructure. A high-quality **Nuxt SaaS boilerplate guide** flips the ratio in your favor. Ready to ship? [Get ShipAhead](https://shipahe.ad){rel=""nofollow""} today and see how fast you can really move. # Buy vs build Nuxt starter kits: ROI, timeline, and revenue ![Founder case study quantifies buy vs build Nuxt: 300 vs 80 hours, 15-day launch, earlier revenue, and clear ROI from a Nuxt SaaS starter kit.](https://shipahe.ad/images/blog/buy-vs-build-nuxt-starter-kits-roi-and-time-to-market/post-309.webp){style="max-width:100%;border-radius:12px"} Every founder building on Nuxt faces two clocks. The hours it takes to ship auth, payments, and admin, and the days until first revenue. This is our quantified case study. We compared building from scratch to buying a Nuxt SaaS starter kit, then shipped paid checkout in 15 days. Below are the inputs, assumptions, and results so you can decide with numbers, not vibes. ## Team, product, and guardrails We were two senior full-stack engineers and a part-time designer. The product was a focused AI assistant for drafting outbound messages. Stack was Nuxt and Vue. Goal was strict. Paid MVP in four weeks to test pricing and positioning. One third of our waitlist was outside the US, so we needed i18n from day one. We aimed for production-grade foundations, not prototypes. Non-negotiables that defined scope and risk: - Authentication: email and password, passwordless magic links, Google OAuth, email verification, session hardening, rate limiting, and tests. - Payments: Stripe subscriptions and one-time credits, proration, taxes and invoices, dunning, refund flows, webhook signature verification, and idempotency guards. - Data: PostgreSQL with a typed ORM and migrations, seeds, and a clean repository pattern. - File storage: S3-compatible signed uploads, private buckets, access policies, and basic lifecycle rules. - Emails: transactional provider with templated password reset, welcome, and receipt emails, plus event-driven triggers. - Admin: users table with search and filters, impersonate user, role management, refunds, and spam bans. - Internationalization: Nuxt i18n with a language switch, runtime locale detection, and translated system strings. - Analytics: page and event tracking for signups and checkout, and a baseline funnel. - SEO: per-page meta, Open Graph images, sitemap, robots rules, and canonical URLs. - Jobs: scheduled tasks for summaries and reminders with retries and visibility. - Content: simple blog and docs using Nuxt Content for release notes and help. - AI: chat and generation with provider switching, token accounting, and safe moderation defaults. - Deployment: preview environments, environment variables, logging, and error tracking. We could build it all, or start from a Nuxt SaaS starter kit like Shipahe.ad that ships these pieces in a consistent, typed codebase and is designed to work with AI coding tools like Cursor and Claude. The goal was not to outsource product thinking. It was to delete undifferentiated engineering work. ## Cost model: build vs buy Assumptions were conservative. Two experienced developers. Code reviews and tests included. No gold plating, but production ready. - Auth and protected routes: 50 hours for signup, login, magic links, Google, email verification, password reset, session guards, and tests. - Payments and checkout: 60 hours for subscriptions and one-time, customer portal, plan changes, invoices and tax, dunning, webhooks, retries, and test matrix. - Database and ORM: 22 hours to set up PostgreSQL, typed models, seeds, migrations, and local scripts. - File storage: 12 hours for S3-compatible uploads, signed URLs, and UI integration. - Admin panel: 24 hours for users list, roles, impersonation, refunds, and bans. - Transactional emails: 16 hours for templating, events, and environment configuration. - Internationalization: 12 hours for wiring locales, toggle, and key extraction. - Analytics: 8 hours for page, event, and funnel tracking. - SEO: 8 hours for meta, OG image generator, sitemap, and robots. - AI chat and generation: 24 hours for UI, server endpoints, provider switching, and moderation. - Scheduled jobs: 6 hours for cron tasks, retries, and observability. - Blog with Nuxt Content: 10 hours for routes, SEO, and styling. - Marketing page: 8 hours for a customizable landing page with pricing blocks. Subtotal was about 260 hours. Add 15 percent for glue work across flows like webhooks, emails, and edge cases. Total landed near 300 hours. At a blended internal rate of 90 dollars per hour, that is about 27,000 dollars before touching core AI logic. With a starter kit like Shipahe.ad, we still had to remove what we did not need, wire our domain logic, and make it ours. Estimated effort: - Branding and landing page customization: 8 hours. - i18n copy and layout review: 6 hours. - Auth options and route guards: 10 hours. - Stripe plans, checkout, and webhook tests: 12 hours. - Database models, seed data, and file storage toggles: 8 hours. - Analytics and SEO configuration: 4 hours. - Transactional emails and a short welcome drip: 6 hours. - Cron jobs for summaries: 3 hours. - AI workflow using provided patterns: 12 hours. Total was about 69 hours to have foundations in place. Even if it stretched to 80 hours, the delta stayed near 220 hours. At 90 dollars per hour, that is 19,800 dollars of engineering time not spent on boilerplate. The license fee was tiny compared to the saved hours. ## Timeline to MVP We held a four-week target to paid users. Buying did not remove work, it moved it to what matters. ### If we built everything ourselves - Week 1: Auth, protected routes, database scaffolding, and email provider setup. - Week 2: Payments, checkout, invoices, and first end-to-end tests. - Week 3: Admin panel, file storage, and transactional emails. - Week 4: i18n, analytics, SEO, and scheduled jobs. - Week 5: AI chat and generation with model switches and moderation, marketing page, and blog. - Week 6: QA, refactors, perf passes, and production hardening. Best case was six weeks for an acceptable MVP, more likely seven to eight with polish and bug fixes. ### If we bought a Nuxt SaaS starter kit - Days 1 to 2: Customize landing page, set language toggle, ship a short blog post. - Days 3 to 5: Configure auth variants and route guards. Invite internal testers. - Days 6 to 8: Set up Stripe subscriptions and one-time credits. Verify webhooks and test dunning. - Days 9 to 10: Build the AI chat and generation flow end to end. - Day 11: Enable analytics and confirm SEO checks pass. - Day 12: Wire transactional emails. Test password reset and welcome. - Day 13: Review admin panel, set moderation rules, add summaries via cron. - Day 14: Bug bash, connect domain, ship. The kit was built to pair with AI coding tools like Cursor and Claude. We used Cursor for refactors and repetitive edits, such as translating strings and adjusting email templates. It sped up routine work without skipping reviews. We hit production in 15 days with paid checkout working. ## Maintenance, security, and updates Foundations create a long tail. Auth edge cases, Stripe API version bumps, email template tweaks, and localization fixes all show up after launch. With bespoke code, we expected 6 to 8 hours a week of maintenance in the first quarter. That includes dependency updates, triage, and support scripts. With a consistent, typed codebase that already included ORM patterns, transactional emails, analytics, SEO, and scheduled jobs, weekly maintenance landed near 2 to 3 hours. The admin panel cut support back-and-forth because we could impersonate a user, issue refunds, or ban spammers without ad hoc scripts. i18n with an in-app toggle made content changes low friction. The blog on Nuxt Content covered release notes without standing up a CMS. Deciding what to build next was another source of waste. A simple feature voting board gave us signal without meetings. We leaned on Feedjolt’s overview of the [best feature voting tools to surface real product demand](https://www.feedjolt.com/en/blog/best-feature-voting-tools-to-surface-real-product-demand){rel=""dofollow""} to pick a lightweight setup that fit our size and avoided roadmap bloat. ## ROI, payback, and decision The numbers close the loop. Launching with a Nuxt starter kit let us buy boilerplate instead of building it. We shipped in 15 days. In the first 30 days live, analytics showed 1,240 unique visitors. Signups converted at 8.6 percent. Paid conversion was 3.1 percent. That produced 33 subscriptions and 18 one-time purchases for a first-month revenue of 2,190 dollars. On the build-everything path, first revenue would have landed around week seven or eight. Engineering time saved was about 220 hours in the first release. At 90 dollars per hour, that is 19,800 dollars of avoided cost. Pulling revenue forward by four weeks added about 2,000 dollars in cash flow and gave us conversion data for pricing. Even if our build-from-scratch estimate was 25 percent too high, buying still wins by a wide margin. The license paid for itself in the first week. The most important outcome was focus. Because foundations were present, we spent energy on the differentiator, the AI chat and generation workflow. We iterated prompts, added model switches, and tuned UX flows that mattered to users. If you are asking whether to buy or build Nuxt for a new product, our conclusion is clear. For a small team trying to ship and learn fast, buying a Nuxt SaaS starter kit is the higher-ROI path. ### Key takeaways - Scope is larger than it looks. Auth, payments, admin, analytics, SEO, and i18n total about 300 hours when built from scratch. - Starting from a Nuxt starter kit cut foundation time to about 70 to 80 hours, saving roughly 220 hours. - We reached paid users in 15 days and pulled revenue forward by about four weeks. - A Nuxt SaaS template with AI chat patterns lets you focus effort on core product value. - Use a lightweight feature voting board to guide roadmap with real demand signals. ## Recommended resources - [best feature voting tools to surface real product demand](https://feedjolt.com) # Deploy Nuxt to Vercel with Custom Domains, Step by Step ![Ship a Nuxt 3 app on Vercel with correct build scripts, env vars, custom domains, previews, caching, redirects, and safe rollbacks. Clear, tested steps.](https://shipahe.ad/images/blog/deploy-nuxt-to-vercel-with-custom-domains-step-by-step/post-375.webp){style="max-width:100%;border-radius:12px"} Shipping a Nuxt 3 app on Vercel is quick if you line up build scripts, runtime config, and DNS the right way. This is the exact deployment flow we use for SaaS apps with auth, payments, i18n, and admin. Follow it once, then repeat it for every feature branch and release without surprises. ## 1) Prepare your Nuxt project for Vercel Lock the basics so your cloud build matches your local build. ### Match Node versions - Use Node 18 or 20. Pick one and use it everywhere. - Add an engines field or an *.nvmrc* so teammates and CI use the same version. ``` ``` ### Set build and start scripts Vercel auto-detects Nuxt, but explicit scripts avoid edge cases. ``` ``` Before pushing, run a local production build to catch SSR issues early: ``` ``` ### Confirm SSR, image domains, and the Vercel preset Most SaaS apps need SSR for auth, server routes, and webhooks. Make that explicit and keep server-only code out of the client bundle. ``` ``` ### Keep server code server-only - Put API handlers under *server/api*. Each file becomes an endpoint. Test them locally with `curl` before you deploy. - Do not reference `window` or `document` in server code. Guard any client-only usage with `process.client` checks. - Enforce protected routes in server middleware so SSR does not leak restricted content. ### Clean artifacts before first deploy Delete *.nuxt* and *.output*, then rebuild. You want the same clean state Vercel will use. ## 2) Configure environment variables and runtime config Separate what the browser can see from what it cannot. Map everything to `runtimeConfig`. ### Define runtime config in Nuxt ``` ``` - Anything in `runtimeConfig.public` can be read in the browser. Only put non-sensitive values there. - On Vercel, variables prefixed with `NUXT_PUBLIC_` are exposed to the client. Everything else is server-only. ### Add env vars per Vercel environment - In Project Settings, add variables for Production, Preview, and Development. Use different keys for staging databases, payment test keys, and email sandboxes. - Use the CLI to sync values locally so your app behaves the same on your machine and in the cloud: ``` ``` ### Know what is read at build time vs request time - SSR pages and API routes read `runtimeConfig` on each request. - Prerendered routes capture values at build time. If a value must update without a rebuild, do not prerender that route. - Use a Preview deployment to test a config change without touching Production. ## 3) Domains, previews, redirects, and caching ### Add and verify your custom domain 1. In your Vercel project, add both the apex domain and the *www* subdomain. 2. Point DNS to Vercel: - Apex: A record to **76.76.21.21**. - www: CNAME to **cname.vercel-dns.com**. 3. Wait for propagation, then pick a primary domain and keep one canonical host. ### Set redirects and headers in Nuxt Keep SEO and analytics clean with a single host and predictable cache policy. Use Nuxt route rules so your config travels with the repo. ``` ``` You can also configure redirects in the Vercel dashboard if you prefer UI control. Keep the rule in one place to avoid conflicts. ### Use Preview deployments with real staging data - Connect your Git repo. Every push creates a unique Preview URL. Treat this as staging for product owners and QA. - Add Preview env vars so previews use staging databases and payment test keys. Never point Preview at production data. - If you need a stable preview hostname, attach a subdomain such as *preview\.example.com* to the Preview environment in Project Settings. ### Static assets - Ship hashed filenames so long-lived caching is safe. Nuxt handles this by default for built assets. - Whitelist any remote image domains to avoid production blocks. ## 4) Ship, verify, and monitor ### Deploy from Git or the CLI - Git-based flow: merge to your main branch to trigger a Production deployment. - CLI flow: `vercel` for a preview, then `vercel --prod` for production. ### Run the critical path checks - Open the homepage and a few deep links. Watch server logs in the Vercel dashboard for slow queries and missing assets. - Exercise APIs with valid and invalid inputs. Example: `curl -i https://yourdomain.com/api/health` and check status codes. - Auth flows end to end: sign up, email magic link, social login, password reset, gated routes. Confirm logout clears cookies and sessions. - Payments in test mode: create a plan, run checkout, verify webhooks update user entitlements and invoices. Confirm idempotency so retries do not double-charge. - Internationalization: switch locales, ensure dynamic routes and metadata render correctly on SSR. ### Turn on your platform features If you built on our Nuxt SaaS starter, you can switch on analytics, SEO meta and sitemap generation, scheduled cron jobs for reports or reminders, and transactional emails for password resets and welcomes immediately after go-live. These ship with the kit, so you do not have to glue them on later. If content and backlinks are your next bottleneck, teams often pair their app with RankGoat to write posts, secure dofollow links, and fix indexing so new features get discovered. ## 5) Roll back fast and avoid pitfalls ### Instant rollbacks Each Vercel deployment is immutable. If production is off, open the last known good deployment in the dashboard and promote it to Production. You can also point your production alias back to that deployment URL using the CLI. The switch is instant because both builds already exist. ### Common pitfalls to avoid - **Missing Preview env vars.** A feature works locally but fails on a branch because the variable only exists in Production. Mirror critical keys with safe staging values. - **Leaking secrets to the client.** Never pass server-only values via `runtimeConfig.public` or with a `NUXT_PUBLIC_` prefix. - **Remote images blocked.** Production will fail requests if domains are not whitelisted. Add them before launch. - **Wrong SSR vs prerender choice.** If a page must reflect per-request data, do not prerender it. If it is mostly static, give it ISR for speed. - **Large serverless bundles.** Keep server routes lean. Import only what you use. Move browser-only packages out of server code. - **No canonical redirect.** Redirect non-www to www or the reverse so SEO and analytics are not split. - **Node mismatch.** Teams on different Node versions see build-only bugs. Pin Node and use the same version in Vercel. ## Key takeaways - Lock Node, scripts, SSR, and image domains before connecting Vercel. - Store secrets in Vercel and map them to `runtimeConfig`. Keep Production and Preview separate. - Attach your custom domain, set one canonical host, and configure redirects in code or the dashboard. - Use route-level caching: ISR for mostly static pages, no-store for auth and APIs. - Rely on immutable deployments to roll back instantly when needed. # How to Build a Nuxt Module: Structure, Options, and Publishing ![Learn how to build a Nuxt module from scratch. Scaffold, add options, ship plugins and composables, test in a playground, and publish without headaches.](https://shipahe.ad/images/blog/how-to-build-a-nuxt-module-structure-options-and-publishing/post-680.webp){style="max-width:100%;border-radius:12px"} You copy the same plugin, composables, and config across projects. A Nuxt module lets you package that setup once so every app gets the same behavior with one install. This guide shows a practical module that registers a plugin, composables, and components, passes options to runtime, tests in a playground, and ships clean to npm. ## What a Nuxt module is and when to write one A Nuxt module runs at dev and build time to extend Nuxt. It can register plugins and composables, add components, ship server handlers to Nitro, tweak Vite and Nitro config, and inject runtime config for the host app. Choose a module when you want to: - Ship a reusable feature like analytics, feature flags, billing UI, or an API client. - Enforce conventions across a team, for example a UI kit, linting, and default build config. - Hide integration details behind a single options object so app code stays clean. Plugins are for one app. A module is for many apps and should install with zero or minimal manual wiring. ## Build a Nuxt module step by step ### 1) Scaffold the module Use the official starter. It includes TypeScript, unbuild, and a ready playground. ``` ``` You get `src/module.ts` for the entry, a `runtime/` folder for code that runs inside the host app, and a `playground/` Nuxt app for local testing. ### 2) Define metadata and options Give the module a name, a config key shown in `nuxt.config.ts`, and sensible defaults. Use `defineNuxtModule` from `@nuxt/kit`. ``` ``` This makes your module configurable via `awesome: { ... }` in a host app’s `nuxt.config.ts`. ### 3) Add runtime code: plugin, composable, and handler Runtime code lives under `runtime/`. Keep the public API small and stable. ``` ``` ``` ``` ``` ``` For client-only or server-only behavior, create `plugin.client` or `plugin.server` files and register the right one. ### 4) Expose components or server routes If your feature ships UI or extra routes, place them in `runtime/components` or `runtime/server` and register as needed. ``` ``` Prefer small, focused components and keep their props stable since host apps may rely on them across versions. ### 5) Use it in the playground The scaffold includes a `playground/` app wired to the local module. Run both together. ``` ``` ``` ``` Create a page and call your composable. ``` ``` If the playground seems stuck on an old build, restart it or run `pnpm -r dev` again so changes in `src/` rebuild. ### 6) Add types and DX polish Type your injections so host apps get IntelliSense. Also export your options type. ``` ``` Point `types` to the built declarations and publish only the build output. Consider an exports map so consumers cannot import sources by accident. ``` ``` If your runtime ships CSS, either import it from the host app or set a narrow `sideEffects` array so tree-shaking does not drop needed styles. ### 7) Package and publish Build, version, and publish to npm. Write a README with install, options, examples, and a changelog link. ``` ``` Test installation in a fresh Nuxt app created with `npx nuxi init`. Verify that `module options → runtimeConfig` works, server handlers mount, and your types resolve in the editor. ## Where modules fit in SaaS and AI projects For a SaaS, a module is the right place to package shared concerns across properties. Examples: - Billing and entitlements: wrap your payment provider client, expose helpers like `usePlan()` and `hasFeature('x')`, and register a secure webhook route. - Auth glue: auto-register a plugin that syncs session state to a composable, and add route rules for protected pages. - i18n defaults: ship a locale detector, default messages, and a directive for number and date formatting. - Marketing baseline: add analytics, SEO helpers, and consistent components like `` and ``. If you want to ship fast, pair your module with a Nuxt SaaS starter kit or a Nuxt boilerplate that already includes authentication, protected routes, an admin area, payments and checkout, i18n, transactional emails, analytics, SEO tools, cron jobs, and a landing page. Your module can focus on domain logic while the base handles foundation work. Building an AI tool for the web follows the same pattern. Wrap your model provider and configuration in a module. Expose a composable like `useAiClient()` with methods for chat, text, and image generation. Support switching models or providers with a single option. Keep pricing, trials, and usage metering in the app or backend, while the module handles the client, types, and error normalization. Early feedback helps shape the roadmap. You can wire in a feedback widget via a tiny plugin inside your module. Feedjolt is a good example of the kind of tool you might integrate to capture votes and rank requests while you iterate. When you buy a Nuxt boilerplate or a Vue Nuxt starter template for a new app, keep your own feature logic inside a module. That lets you swap the base later without a rewrite and keep the same composables and components across products. ## Common pitfalls and fixes - **Missing transpile for runtime.** If host apps error on syntax or imports, add `nuxt.options.build.transpile.push(resolver.resolve('runtime'))` in `setup`. - **Options not available at runtime.** Mirror module options into `runtimeConfig.public`. Read them with `useRuntimeConfig` in your plugin and composables. - **Wrong import paths after publish.** Publish only built files. Set `files: ["dist"]` and add an `exports` map to block deep imports into `src/`. - **Plugins run in the wrong environment.** Use `plugin.client` or `plugin.server` filenames, or guard logic with `process.client`/`process.server`. - **Playground uses a cached build.** Restart the playground or run `pnpm -r dev` so changes in `src/` rebuild the module. - **Global types not picked up.** Ensure your `dist/types.d.ts` is shipped and referenced by `types` in `package.json`. If you generate multiple d.ts files, re-export them from a single entry. - **Bundled dependencies break the host app.** Keep framework and Nuxt as peer dependencies. Do not bundle Vue or Nuxt types into your dist. - **Server routes collide.** Prefix your routes, for example `/awesome/*`, to avoid conflicts in host apps. ## Key takeaways - A Nuxt module packages reusable setup for many apps: plugins, composables, components, routes, and build config. - Scaffold with `nuxi`, define options with `defineNuxtModule`, and add runtime code under `runtime/`. - Test in a playground before publishing so you catch path, transpile, and runtime config issues early. - For SaaS and AI work, keep domain features in a module and let a Nuxt starter kit handle auth, payments, admin, analytics, and SEO so you ship fast. ## FAQ ### What is the difference between a Nuxt plugin and a Nuxt module? A plugin runs in one app and sets up runtime behavior. A module runs at build time and can add plugins, composables, components, server routes, and tweak build config across many apps. ### How do I test a Nuxt module locally before publishing? Use the scaffolded playground app, point it at your module’s local entry, and run a workspace dev script so the module rebuilds when you edit code. ### Can I make parts of my module client-only or server-only? Yes. Use separate plugin files like plugin.client.ts or plugin.server.ts, or guard code with process.client and process.server checks. ### How should I expose configuration from my module at runtime? Mirror options into runtimeConfig.public (or private) during setup, then read them from useRuntimeConfig in your plugin and composables. ### What Node and Nuxt versions should my module support? Target the current LTS version of Node and add a Nuxt peerDependency such as ^3.x. Test in a fresh Nuxt app to confirm compatibility. # How to Build a SaaS with AI Coding Agents – Step-by-Step Building a SaaS used to be a lonely, month-long slog. You were the designer, the coder, and the QA team. In 2026, that’s no longer the case. You can now build with a team of AI agents that handle the heavy lifting while you act as the architect. But there's a catch: AI is only as good as the foundation you give it. If your code is a mess, the AI will just make it a faster mess. Here is the exact workflow I use to leverage AI agents and a solid Nuxt foundation to launch products in days, not months. --- ## What Are AI Coding Agents? Unlike standard autocomplete tools, **autonomous coding agents** can understand your entire project. They can read your documentation, find bugs across multiple files, and write complex logic based on a simple sentence. Why founders are switching to an AI-first workflow: - **10x Speed:** You spend seconds describing a feature instead of hours coding it. - **Lower Barrier to Entry:** You don't need a Computer Science degree to build a professional app. - **Instant Debugging:** AI finds and fixes errors before you even notice them. To get the most out of these **AI coding assistants for SaaS**, you need a structured foundation. This is where [ShipAhead](https://shipahe.ad){rel=""nofollow""} comes in. --- ## Step 1: Establish a Clean Foundation AI tools work best when they aren't guessing. If your code is messy, the AI will produce messy results. By starting with a professional boilerplate, you give the AI a "clean map" to follow. [ShipAhead](https://shipahe.ad){rel=""nofollow""} provides: - A standardized Nuxt 4 and Tailwind CSS setup. - Clear naming conventions for database tables and API routes. - An architecture optimized for **accelerate SaaS development**. **Pro Tip:** Your first step should be installing your boilerplate. This ensures that every line of code the AI writes follows a proven, scalable pattern. --- ## Step 2: Optimize Your AI Workflow To **build a SaaS fast with AI**, you need the right tools. We recommend using **Cursor** combined with **Claude 3.5 Sonnet** (or the latest model). 1. **Index Your Project:** Let Cursor scan your files so it knows exactly how your auth and database work. 2. **Use a Developer Log:** Create an `AGENT.md` file. List your technical choices, your preferred styling rules, and how you handle state. 3. **Reference Your Docs:** If you are using a specific library, provide the AI with the documentation URL. --- ## Step 3: Writing Productive Prompts The secret to building with AI isn't just "asking." It is about providing context. Instead of saying "Build a dashboard," try being specific. **Example Prompt:** > "Using our existing UI library, create a new 'Team' page. Include a list of members from the 'users' table, a button to invite new members via email, and a toggle to change their role between 'Admin' and 'Member'." Because you are using a structured foundation, the AI knows exactly where the users are stored and how the buttons should look. --- ## Step 4: The Human-in-the-Loop Review The AI is your assistant, not your replacement. You must still be the architect. - **Review Every Commit:** Always look at what the AI changed. - **Run Local Tests:** Ensure the new feature hasn't broken the login flow or payment system. - **Iterate:** If the styling is off, simply ask the AI to "Make the buttons more rounded like the home page." --- ## Step 5: Launching and Scaling Once the AI has helped you build your core features, use it to help you go live. Ask it to: - "Generate a Sitemap for my Nuxt app." - "Write the meta descriptions for my blog posts." - "Help me configure the environment variables for Vercel." --- ## The Future of Shipping The "solo founder" is more powerful than ever. By using **Build SaaS with AI agents**, you can compete with companies that have 10x your budget. Stop waiting for a co-founder or a bigger budget. Start with [ShipAhead](https://shipahe.ad){rel=""nofollow""}, fire up your AI assistant, and build your business today. # How to Build and Sell an AI Tool Online in 2026 It feels like everyone is building an AI tool these days. If you’ve been scrolling through X wondering, *"How do I actually build and sell one of these myself?"* you're in the right place. The good news? In 2026, the technical barriers are basically gone. You don’t need a PhD in machine learning or a server farm to build something people will pay for. All you need is a specific problem, an API, and a stack that doesn't get in your way. Here is the exact blueprint I use to go from idea to first sale. --- ## Step 1: Finding Your Niche We've all seen a million generic "ChatGPT wrappers." Don't build the million-and-first. If you want to make a dent, you have to get hyper-specific. - **Solve a super specific workflow:** "An AI blog writer" is too broad. But "An AI report generator for freelance home inspectors"? Now you're talking. - **Bring your own data:** AI is basically magic when you hook it up to unique data. Find a weird proprietary API and feed that context into the LLM. - **Nail the UX:** Sometimes, people aren't paying for the AI; they are paying because you made the AI actually easy and pleasant to use. Never underestimate a beautiful interface. --- ## Step 2: Picking Your Brain (The API) You don’t have to reinvent the wheel. Just pick the off-the-shelf brain that fits your app best. 1. **Anthropic (Claude):** If your tool involves deep reading, nuanced writing, or coding, Claude 3.5 Sonnet is honestly incredible. 2. **OpenAI:** The old reliable. GPT-4o is fast, solid, and everyone trusts it. 3. **OpenRouter:** Can’t decide? Don't! OpenRouter gives you one single API key that lets you seamlessly switch between Llama, Anthropic, and OpenAI on the fly. --- ## Step 3: Skipping the Boring Stuff When inspiration strikes, the last thing you want is to spend two weeks messing around with auth tokens and database schemas. Your energy should go into the feature that actually makes you money. This is exactly why so many indie hackers use boilerplates. A setup like **ShipAhead** gives you the entire Nuxt foundation ready to go on day one. It hands you: - **Authentication:** Login logic is already handled. - **Stripe Payments:** Ready to take people's money. - **Database (Drizzle ORM):** Ready to save your users' data without the headache. By letting a boilerplate handle the plumbing, you can jump straight into building the cool AI features that set your product apart. --- ## Step 4: Making Money (Setting Up Payments) How do you actually plan to charge people? - **SaaS Subscriptions:** The holy grail. A flat monthly fee for a set amount of usage. - **Pay-As-You-Go:** Buying credits works great if your API costs are unpredictable. - **Lifetime Deals:** A sweet one-time payment. It brings in fast cash early on but be careful—supporting users forever is a long time. Stripe makes all of this a breeze. (And yes, if you grabbed a boilerplate earlier, Stripe is usually already wired up for you). --- ## Step 5: Getting Those Sweet, Sweet First Users Alright, the app is live. Now you have to convince strangers to try it. - **Build in Public:** Share the messy behind-the-scenes on X or LinkedIn. People love an underdog story. If you want to put this on autopilot, a tool like [LiFast](https://lifa.st){rel=""nofollow""} is awesome for scaling your LinkedIn B2B outreach without spending all day on it. - **Tap into Reddit:** Subreddits are goldmines for early users complaining about the exact thing your app fixes. Instead of manually digging through posts all day, [MediaFast](https://mediafa.st/?atp=5lU9lT){rel=""nofollow""} can automatically find those keyword mentions for you, so you can join the conversation naturally. - **Launch on Product Hunt:** A classic right of passage. A good launch day can easily scoop up your first hundred paying users and secure some solid backlinks. - **Treat Early Users Like Gold:** Once they sign up, you *have* to listen to them. Dropping a quick widget onto your site lets you handle support and feature requests instantly, proving to your users that a real human is listening. - **Play the SEO Game:** Start churning out targeted blog posts so Google starts doing the heavy lifting for you over time. ## Wrapping Up Getting an AI tool off the ground in 2026 is honestly a blast. Start small, talk to people to make sure they actually want it, plug into OpenRouter, and skip the boring dev work with a boilerplate like ShipAhead. It's time to stop wondering *"how do I build and sell an AI tool online?"* and start actually building the thing. # How to Find Profitable SaaS Ideas in 2026 – A Complete Guide The biggest mistake founders make is building in a vacuum. You spend six months perfecting an app only to realize that nobody actually wants to pay for it. I've learned the hard way: You don't need a "revolutionary" idea to build a profitable SaaS. You just need to solve a real, annoying problem for a specific group of people. Forget the "shower thoughts." Here is the tactical framework I use to find niches with high demand and low competition—and how to validate them before you write a single line of code. --- ## The Rule of Profitable Ideas A great SaaS idea isn't a "shower thought." It is a solution to a recurring headache. If people are already complaining about a problem, they are likely willing to pay to make it go away. When searching for **B2B SaaS ideas**, look for tasks that are: - **Repetitive:** Something people have to do every day. - **Slow:** Something that takes hours but should take minutes. - **Expensive:** Something that requires hiring an expert or a large team. --- ## 4 Simple Ways to Discover Your SaaS Niche ### 1. The "Scratch Your Own Itch" Method Think about your own workday. What tools do you use that are slow, ugly, or frustrating? If you are a developer, a marketer, or a lawyer, there is likely a **low competition SaaS** niche hiding in your daily workflow. ### 2. Look for "AI-Native" Replacements Many established tools were built 10 years ago. They are bloated and weren't designed for AI. Can you build an AI-first version of an existing tool that is 10x faster? This is a massive opportunity for **SaaS niche discovery**. ### 3. Mine the "Complaint Departments" Go where people are unhappy. Sites like Reddit, X (Twitter), and G2 are gold mines. Search for: - "I hate it when [Software Name]..." - "Why is there no app to..." - "How do I do X without using [Expensive Tool] ?" ### 4. Shadow a Non-Tech Business Owner Talk to a plumber, a restaurant owner, or a real estate agent. Ask them: "What is the most boring part of your week?" They aren't looking for "cutting-edge tech"; they are looking for a way to save two hours on their Saturday. --- ## How to Validate Your SaaS Concepts Before you touch your keyboard, you must **validate your SaaS concepts**. Validation means getting evidence, not just "opinions." - **Step 1: The Search Test.** Use Google Keyword Planner to see if people are actually searching for terms related to your problem. - **Step 2: The Landing Page Test.** Build a simple page using your [starter kit](https://shipahe.ad){rel=""nofollow""} and see if people will give you their email to hear about the launch. - **Step 3: The Pre-Sale Test.** Can you get 5 strangers to pay you $50 for a lifetime deal or a beta access? If they pay before the app exists, you have a winner. --- ## Stuck? Use Our Free Idea Generator If you are still looking for inspiration, we created a tool just for you. Our [AI SaaS Idea Generator](https://shipahe.ad/ai-saas-idea-generator){rel=""nofollow""} analyzes current market trends to suggest **profitable SaaS ideas for 2026** tailored to your skills. --- ## From Concept to Launch in Days Finding the idea is the hard part. The coding shouldn't be. Once you've identified your niche, don't spend months on the setup. Use [ShipAhead](https://shipahe.ad){rel=""nofollow""} to get your core features live. It handles the logins, the payments, and the database, so you can focus 100% on the unique part of your idea. --- ## Final Thoughts Great ideas are everywhere. The difference between a "wantrepreneur" and a founder is execution. Find a problem, validate it, and start shipping. Ready to build? Grab [ShipAhead](https://shipahe.ad){rel=""nofollow""} and turn your idea into a real business today. # How Much Time Does a Nuxt Starter Kit Actually Save? The biggest question I get from developers isn't "how do I build this?" It's "**is this still worth the effort?**" In 2026, the SaaS market is crowded. But the math has changed. The reason most projects fail isn't a lack of features—it's a lack of speed. If you spend three months building the foundation, you've already lost to the founder who launched in three days. ### The Real ROI of Speed Let's look at the numbers. This is the difference between building your foundation from scratch versus using a professional [Nuxt starter kit](https://shipahe.ad){rel=""nofollow""}. | Feature | Building From Scratch | Using a Boilerplate | Time Saved | | :-------------------- | :-------------------- | :------------------ | :-------------- | | **Authentication** | 15-20 Hours | < 5 Minutes | \~18 Hours | | **Stripe Billing** | 20-30 Hours | 10 Minutes | \~25 Hours | | **Admin Dashboard** | 40+ Hours | 0 Minutes | \~40 Hours | | **SEO & Meta Tags** | 10 Hours | 0 Minutes | \~10 Hours | | **Total Launch Time** | **3-6 Weeks** | **< 48 Hours** | **\~90+ Hours** | When you realize a boilerplate saves you **90+ hours of development**, the question changes from "is SaaS worth it?" to "**how fast can I ship?**" --- ## Why the SaaS Business Model is Still King To understand the **future of SaaS business**, we have to look at how much the barrier to entry has dropped. | Feature | The Old Way (Pre-2023) | The 2026 Way | | :------------------- | :------------------------ | :------------------------------ | | **Development Time** | 3-6 Months | 3-7 Days | | **Setup Cost** | Thousands in dev hours | A few hundred for a boilerplate | | **Team Size** | 2-3 Developers | 1 Indie Hacker + AI Agents | | **Maintenance** | Complex server management | Serverless & Auto-scaling | Because it is so much cheaper and faster to launch, the risk of **starting a SaaS today** is a fraction of what it used to be. --- ## Why the SaaS Business Model is Still King Software as a Service remains the best business model ever created for one reason: **Recurring Revenue.** Unlike selling a physical product or a one-time service, a SaaS provides: - **Predictable Cash Flow:** You know exactly how much you're making next month. - **High Profit Margins:** Once the software is built, the cost of adding a new user is nearly zero. - **Asset Value:** A profitable SaaS with stable churn can be sold for 3x–5x its yearly profit. --- ## 3 Pillars of a Successful Indie Hacker SaaS in 2026 If you want to succeed, you need a different strategy than the VC-backed giants. ### 1. Solve a "Vertical" Problem Don't try to be "Slack for everyone." Be "The communication tool for boutique dental clinics." When you narrow your focus, your marketing becomes cheaper and your users become more loyal. ### 2. Prioritize Time-to-Market In 2026, speed is a feature. If you spend three months building in secret, a competitor will launch in three days using a [starter kit](https://shipahe.ad){rel=""nofollow""} and steal your users. Use [ShipAhead](https://shipahe.ad){rel=""nofollow""} to handle the infrastructure so you can go live while the idea is fresh. ### 3. Build an "AI-First" Experience Don't just add an AI chatbot to a legacy app. Build your SaaS around an AI workflow that saves your users hours of manual work. That is where the real value lies in the **SaaS market trends** of today. --- ## SaaS Profitability Analysis: Can You Still Win? Let's look at the numbers. If you solve a problem that saves a business $500 a month, charging them $50 is an easy sell. - **Cost of Goods Sold (COGS):** With serverless hosting and modern databases, your monthly cost per user is pennies. - **Customer Lifetime Value (LTV):** If a user stays for 24 months at $50/mo, that's $1,200 from a single customer. The math for a solo founder remains incredibly attractive. --- ## The Verdict Is building a SaaS worth it? Absolutely. But only if you stop acting like a 2015 startup. Don't over-engineer. Don't hire a team. Don't build your own login system. Grab [ShipAhead](https://shipahe.ad){rel=""nofollow""}, leverage AI, and build a business that serves a real niche. The opportunity has never been bigger for those who ship fast. # Nuxt 3 authentication with email, magic links, and Google ![Set up Nuxt 3 auth with email/password, magic links, and Google. Secure sessions, protect routes, and ship faster with a production-ready starter.](https://shipahe.ad/images/blog/nuxt-authentication-with-email-magic-links-and-google/post-479.webp){style="max-width:100%;border-radius:12px"} Authentication is the first real test for a Nuxt app. You need email and password for confidence, magic links for a low-friction first session, and Google for one-tap sign in. You also need clean redirects, protected routes, and sessions that do not break under real traffic. This is the playbook I use when building SaaS and AI tools with Nuxt 3 and what Shipahe.ad ships out of the box so you can make your first dollars online without burning weeks on plumbing. ## Plan the flows before you code Decide exactly how users enter and recover access. Map these paths: - Sign up: fields collected, welcome email, post-signup redirect. Keep it to email and password. Add name later in onboarding. - Sign in: email + password, magic link, and Google as distinct, obvious choices. Always fall back to email-only recovery. - Password reset: request page, token lifetime, confirmation page, and whether you auto sign in after a successful reset. List your emails and the triggers: welcome, verification if required, magic link, reset request, and reset success. Write the subject lines now so you avoid vague defaults later. For multi-locale apps, draft both the UI copy and emails per locale so your i18n is consistent from day one. ## Email/password and magic links that feel fast and safe Email/password is your baseline. Magic links remove friction for first-time users and demos. Both should land on the same account. 1. **Pages and UX.** Use three pages: /signup, /login, /reset. Keep forms short. On magic link submit, swap the form for a clear “Check your email” state and show which address you sent to. For all auth actions, show definitive success and failure states. 2. **Server-side hashing and validation.** Hash with Argon2id on the server. Enforce a minimum length and check common passwords with a local entropy check such as zxcvbn. For breach checks, hit the Have I Been Pwned k-anonymity API server side. Rate limit by IP and user ID. 3. **Password reset with short-lived tokens.** Generate a random token, store a hashed version with user ID, purpose, and an expires\_at no longer than 15 minutes. Send a link to a page that verifies and consumes the token once. On success, invalidate the token and clear other active sessions for that user. 4. **Magic link issuance and redemption.** Create a single-use token bound to email and an expiry of 10–15 minutes. Include a jti so you can revoke the exact token on redemption. Consider adding a fallback 6–8 digit code in the email for copy-paste. 5. **Email deliverability that actually lands.** Authenticate your domain with SPF, DKIM, and DMARC. Use a dedicated subdomain for transactional mail, like mail.yourapp.com. Include the expiration time and the requester IP in the email so users can spot suspicious activity. Minimal Nuxt server handlers for login and sessions could look like this: ``` ``` In Shipahe.ad, email/password, reset, and magic links are already wired with templates, rate limits, and a single account per email. You focus on copy, not the edge cases. ## Google sign-in without duplicate accounts Google reduces friction for users on Chrome and Android. Keep it tight and link to existing accounts instead of creating clones. 1. **Create OAuth credentials.** In Google Cloud Console, add an OAuth client with your local and production redirect URIs. Scopes openid email profile are enough for sign-in. Use a strict Authorized JavaScript origins list. 2. **Defend the callback.** Verify state for CSRF and nonce for replay. Validate the ID token with Google’s certs and check aud, iss, and exp. Extract the *verified* email only. 3. **Link by email, not by provider ID alone.** If a user with the same verified email exists, attach the Google provider to that user. Only create a new user when there is no match. Store provider name and provider user ID. Keep refresh tokens only if you call Google APIs later, and encrypt them at rest. Shipahe.ad includes Google as a toggle. The callback handler already verifies state and nonce and links to an existing account by email to avoid duplicates. ## Protect routes and manage sessions on both sides Client checks improve UX. Server checks provide security. Use both. 1. **Client route guards.** Add route middleware for gated pages. Redirect anonymous users to /login and redirect authenticated users away from onboarding or auth pages when appropriate. ``` ``` 2. **Server enforcement.** Never trust the client. Wrap server routes with a session check and role check. ``` ``` :br 3. **Cookie strategy.** Put session IDs and refresh tokens in httpOnly, Secure cookies. Use SameSite=Lax for most apps. If you serve the app and API across different domains, use SameSite=None and Secure on HTTPS only. Do not store tokens in localStorage. 4. **Short access, longer refresh, rotate often.** Keep access tokens short lived. Rotate refresh tokens on every use and revoke the previous one to kill replay. On logout, delete cookies and revoke refresh tokens, and broadcast a logout event across tabs with the Storage API. 5. **CSRF and state.** Protect state-changing POST routes with CSRF tokens. For OAuth, verify state and nonce every time. ### Common pitfalls - **Duplicate accounts.** Always link Google and magic-link sign-ins to the same user by verified email. - **Overlong magic links.** Keep tokens short lived and single use. Invalidate on redemption. - **Weak email deliverability.** Set SPF, DKIM, and DMARC. Use a transactional subdomain. Clear subjects beat clever ones. - **Client-only checks.** Guard server routes. Client redirects help UX, not security. - **Leaky storage.** Use httpOnly cookies. Avoid localStorage for secrets. - **No rate limits.** Throttle login, reset, and magic-link endpoints. ## Build faster with a Nuxt SaaS starter kit After sign-in works, the next drop-offs are onboarding and checkout. Send users to a crisp setup checklist, then a single checkout that supports one-time and subscriptions. Fire a receipt email that includes plan, amount, and a support contact. In practice, steady operations beat clever features. A good external example is this [operations guide to selling more on Mercado Libre](https://meliboost.com/blog/how-to/como-vender-mas-en-mercado-libre-tacticas-accionables/){rel=""dofollow""}, which shows how software centralizes orders, messages, inventory, and facturación CFDI Mercado Libre so teams stop guessing and start shipping orders. Same idea here. Tight systems around checkout, messaging, and receipts cut support tickets and churn. If you want a working base instead of a blank repo, Shipahe.ad is a Nuxt starter kit with production auth in place. You get: - User accounts with email/password, magic links, Google sign-in, password reset, and route protection already wired. - Transactional email templates with i18n so your login and receipt messages match the user’s locale. - An admin dashboard to view users, set roles, and ban obvious spammers. - Checkout flows for one-time and subscriptions with swappable providers like Stripe or Paddle, plus webhooks and dunning hooks you can enable later. - Analytics for pageviews, signups, and key actions so you can spot friction without adding a second tool on day one. - SEO helpers for meta, Open Graph images, and sitemaps, and a landing page you can customize by editing copy. - Deployment presets for modern hosts and clean .env handling across local, staging, and production. It is designed to play nicely with AI coding tools like Cursor and Claude so small changes and repetitive edits stay quick while you focus on shipping your product. ### Key takeaways - Plan sign up, sign in, and recovery before writing code to avoid rework. - Implement email/password and magic links with the same account and add Google without creating duplicates. - Protect pages on the client and the server. Store sessions in httpOnly cookies and rotate refresh tokens. - Watch auth metrics and email deliverability so you catch configuration issues early. - A Nuxt boilerplate like Shipahe.ad lets you launch faster without rebuilding the basics. ## Recommended resources - [operations guide to selling more on Mercado Libre](https://meliboost.com) # Nuxt email templates: 7 examples for SaaS notifications ![Seven Nuxt email templates with subject lines, fields, i18n, cron, and deliverability tips. Ship reliable welcomes, receipts, trials, and more from day one.](https://shipahe.ad/images/blog/nuxt-email-templates-7-examples-for-saas-notifications/post-284.webp){style="max-width:100%;border-radius:12px"} Your SaaS earns trust every time an email lands on time, with the right details, and a clear next step. In Nuxt you can wire these messages to real product events and ship fast if you standardize your templates and data. Below are seven templates that cover the moments that matter, plus concrete Nuxt implementation notes for speed and reliability. ## Core transactional templates These messages confirm identity and set expectations. Keep them short, single purpose, and consistent across locales. - **Welcome**:br Goal: confirm the account and point to one action. Trigger on signup or first verified login. :br Subject ideas: "Welcome to \[Product] — your next step" or "You are in. Start with \[Feature]". :br Include: first name, account email, a single CTA to the dashboard or onboarding step, support link in the footer. :br Nuxt note: emit an auth event after user creation, enqueue an email job with the user locale, and render HTML from one template plus a text-only part. Set a short preheader like "Set up your first project in two minutes." - **Password reset**:br Goal: give a safe, time-boxed path to change credentials. :br Subject ideas: "Reset your \[Product] password". :br Include: a single reset button, link expiry window, and instructions if the request was not made by the user. :br Security: store a hashed, single-use token with a TTL. Invalidate on first use. Log IP and timestamp for audit. In Nuxt, route tokens to a protected page that checks validity on load and blocks form submission if expired. - **Account banned**:br Goal: communicate a decision and reduce back-and-forth. :br Subject ideas: "Your \[Product] account status". :br Include: decision summary, high-level reason mapped to policy, and a support contact if appeals are allowed. :br Safety: if access is fully revoked, do not link back into the app. If partial restrictions apply, link only to a read-only billing or export page. ## Billing and lifecycle emails Revenue-related messages must be precise and predictable. Standardize fields so your content stays the same even if you swap payment providers. - **Payment receipt**:br Goal: provide proof of payment with zero ambiguity. :br Subject ideas: "Receipt for \[Plan], \[Month] \[Year]". :br Include: plan or product, period or purchase date, last4 of card or payment method, subtotal, tax, total, currency, and a button to view the invoice. :br Nuxt note: define a provider-agnostic schema, for example { amount\_total, currency, tax\_amount, line\_items\[], invoice\_url, customer\_name }. Map Stripe or other provider payloads to this schema before rendering. Keep the layout simple with labels on the left and values on the right. Add a plain text footer clarifying that this serves as a tax invoice where applicable. - **Trial ending**:br Goal: make the next step obvious before access lapses. :br Subject ideas: "Your trial ends in 3 days" and on the final day "Your trial ends today". :br Timing: send 3 days before, on the day, and optionally 3 days after with a grace reminder. :br Include: days remaining, current plan, and two buttons side by side — Upgrade and Manage subscription. :br Scheduling: store trial\_end at signup. Use a scheduled task to query accounts where now is within the notice window, then enqueue messages by locale to avoid bursts. - **Failed payment**:br Goal: help customers fix billing without fear or confusion. :br Subject ideas: "We could not process your payment". :br Include: what failed, when the next retry occurs, and a direct button to update the payment method. :br Nuxt note: handle webhook events like invoice.payment\_failed, compute the next attempt time from the provider schedule, and send one email per invoice id. Use idempotency by storing the event id you processed to avoid duplicates. ## Product updates that drive adoption Feature announcements should be short, benefit led, and linked to a single action inside the app. Keep them out of transactional streams and respect preferences. - **Update or feature announcement**:br Goal: explain the value and let users try it in one click. :br Subject ideas: "New: faster filters for large projects" or "Save time with bulk actions in \[Product]". :br Include: a one-sentence benefit, a bulleted highlight of what changed, and one CTA that deep-links to the feature configured for the user role. Add a brief note on how to revert or find settings if relevant. :br Example context: hiring teams using [resume screening software](https://marxel.co){rel=""dofollow""} benefit from faster shortlist generation that reviews large batches of resumes against criteria and produces an explainable list for reviewers. Announce that improvement and link straight to the new filter setup with a signed, one-click deep link. :br Segmentation: send only to active users of related modules or plans. Suppress for users who have not logged in recently to avoid spam complaints, or include a "See what is new" digest instead. ## Localization, scheduling, and deliverability in Nuxt Design your emails so they scale across languages and time zones, arrive when they should, and clear spam filters. - **i18n structure**:br Use shared translation keys across all templates. Keep placeholders stable, for example: auth.reset.cta = "Reset your password" and billing.receipt.total = "Total: {amount}". Store locale with the user and pass it through your email queue so templates and date formatting are consistent. - **Date, time, and currency**:br Render with Intl.DateTimeFormat and Intl.NumberFormat so formats match user expectations. Respect local time zones in subject lines where space is tight, for example "Due on 12 Oct, 9:00". Use ISO timestamps in machine-readable attributes if you include structured data. - **Scheduling and retries**:br Set up a scheduler to send lifecycle notices at exact times. Use a daily job for trial reminders and a minute-level job for password resets or webhook-driven billing events. Implement exponential backoff for transient send failures and mark messages for manual review after the final retry. Persist a lightweight delivery log with email type, user id, locale, and provider message id so support can answer "did you send it" questions fast. - **Design and accessibility**:br Keep content width around 600 px, minimum 14 px body text, and clear contrast for buttons. Provide a text-only alternative part for every email. Write a 40 to 90 character preheader that complements the subject. Use descriptive button labels like "View invoice" instead of "Click here". Add alt text for logos and screenshots. Avoid images that contain critical text. - **Authentication and reputation**:br Authenticate your sending domain with SPF, DKIM, and DMARC before go-live. Use a consistent From name and a working Reply-To that routes to your support system. Warm up new domains gradually. For product updates, include a visible manage-preferences link and honor it. Keep link counts low in transactional messages. - **Templates and partials**:br Use a single header and footer partial across all templates so you can roll out branding changes once. Favor simple, table-based HTML or a compiled framework that outputs it. Test against light and dark mode in major clients. Snapshot tests on your render functions catch accidental copy changes before they ship. ## Key takeaways - Standardize seven essentials: welcome, reset, receipt, trial notices, failed payment, ban notice, and a focused product update. - Keep every email single purpose with one CTA and predictable fields so users act fast. - Drive sends from real events and schedules. Use webhooks for billing and daily jobs for trials. - Localize early with stable placeholders and format dates, times, and currency per user locale. - A Nuxt SaaS boilerplate with transactional templates, i18n, and scheduling lets you launch faster than hand-rolling from scratch. ## Recommended resources - [resume screening software](https://marxel.co) # Nuxt Middleware: A Practical Guide for SaaS and AI Apps ![Use Nuxt 3 middleware to guard auth, subscriptions, locales, admin, and analytics. Concrete patterns, code, and pitfalls for SaaS and AI apps.](https://shipahe.ad/images/blog/nuxt-middleware-practical-guide-saas-ai-apps/post-692.webp){style="max-width:100%;border-radius:12px"} If your app has logins, paid features, multiple languages, and an admin area, routing rules pile up fast. Nuxt middleware keeps those rules consistent, testable, and easy to change without scattering checks across components. Below is a practical stack we use on SaaS and AI tools. It favors small, named middlewares, clear redirects, and server-first checks so users never see protected pages flash. ## What middleware does in Nuxt 3 Nuxt 3 gives you two layers: - **Route middleware**. Runs before navigating to a page. Ideal for auth, plan gating, locale redirects, analytics. Files live in */middleware*. Name them for selective use, or add *.global* to run on every navigation. - **Server middleware**. Runs on the server for every request handled by Nitro. Use it for request logging, bot filtering, strict headers, and webhook signature checks. Files live in */server/middleware*. Route middleware runs on both server and client. You can make decisions on the first request on the server to avoid flicker, then reuse the same checks on the client for internal navigations. ``` ``` ## Build a reliable middleware stack 1. ### Write the rules before code List the routes and the guardrails they need. A typical SaaS set: - Public routes anyone can view. - Protected routes for logged-in users. - Paid routes for active subscribers. - Admin-only routes for your team. - Language-aware routes that honor a user’s locale. :brWrite the behavior and the failure path in plain language. Example: “If a non-subscriber visits /generate, redirect to /pricing and remember where they came from.” This becomes the acceptance test for your middleware. 2. ### Create an authentication guard Add */middleware/auth.ts* and redirect to login when there is no session. Always carry the intended destination. ``` ``` :brIf you use a Nuxt SaaS starter, session state and redirects are already wired, so the guard is a thin wrapper around a single source of truth. 3. ### Gate paid features Check subscription status in */middleware/paid.ts*. If missing or expired, send users to pricing or checkout and preserve the next URL. ``` ``` :brKeep plan state cached in session or a small store that is filled on login or page load so the middleware does not trigger extra round trips. 4. ### Protect admin routes Verify role in */middleware/admin.ts*. Fail closed to a safe page. ``` ``` :brMirror the role model from your Admin Panel to avoid drift. Admin checks should be strict and boring. 5. ### Handle language with a global locale middleware Pick a default on first visit, then respect user choice. Prefix the filename to control order. ``` ``` :brLet the in-app language switch update the cookie or profile so the middleware follows the user’s decision. 6. ### Track analytics without flicker Record pageviews in a global middleware. Emit on the server when possible, then fall back to a client call. ``` ``` :brKeep event names consistent so you can answer, “Which protected routes cause the most logins?” or “Which plan gates are hit most often?” 7. ### Use server middleware for low-level checks Put request-wide concerns in */server/middleware*. Keep handlers fast and stateless. ``` ``` 8. ### Attach middleware in one obvious place Use named middleware in pages via `definePageMeta`. Leave a short comment at the top describing the policy. ``` ``` :brDocument exceptions in the same way. Login, signup, pricing, and error pages should be exempt from *auth* and *paid*. ## Patterns that hold up in production ### Guest-to-paid upgrade A public landing page links to an AI feature page that requires both *auth* and *paid*. If the visitor is logged out, send them to sign up. If logged in but not paid, send them to checkout. On success, return to the feature page with inputs intact so they can continue the workflow. ### Localized onboarding The first visit sets the initial locale from headers and redirects to a language-prefixed path. Thereafter, respect the user’s switch. This avoids loops and fights with the user’s choice. ### Admin-only moderation Admin routes run the *auth* and *admin* middlewares. Fail closed to the dashboard. Keep the Admin Panel and middleware checking the same role source of truth. ### AI usage gates Gate costly operations like generation, uploads, or long-running jobs. Apply *auth* and *paid* to chat, text, and image routes. That lets you measure demand and control spend from day one. ## Pitfalls, tests, and tooling - **Infinite redirects**. Whitelist login, signup, pricing, and error pages. Add a quick check at the top of *auth* and *paid* to skip on those routes. - **Client-only checks cause flicker**. Ensure the critical checks run during the first server navigation so protected content never flashes. - **Slow async in middleware**. Do not fetch user or plan data on every navigation. Hydrate a small store on login or initial load and read from it. - **Order surprises**. Global middlewares run in filename order. Prefix them, for example *10-locale.global.ts* and *20-analytics.global.ts*, so intent is obvious in reviews. - **Untested failure paths**. Write unit tests for each rule and a few end-to-end checks: expired plan, revoked admin role, missing locale cookie. Middleware is small, but everything around it is not. A ready-to-buy Nuxt boilerplate removes a lot of setup. The shipahe.ad Nuxt starter includes protected pages, multiple authentication options, payment processing for one-time and subscriptions, multi-language support, transactional emails, a typed database with ORM, S3-compatible file storage, AI chat and generation with switchable models, cron jobs, a blog powered by Nuxt Content, analytics tracking, SEO tools, and a prebuilt landing page. It is built to work well with AI coding tools like Cursor and Claude. As you refine rules, capture what feels rough for users. A public feedback workflow makes patterns obvious. See their [practical guide to product feedback and running a feature voting board](https://www.feedjolt.com/en/blog/product-feedback-management-for-startups-practical-guide){rel=""dofollow""} for a simple way to collect requests, auto-merge duplicates, and rank what to build next. If you want a Nuxt SaaS starter that keeps middleware focused on policy while auth, payments, i18n, and analytics are already wired, a production-grade template will save weeks. Buy a boilerplate when you want to launch sooner and spend your time on product value, not plumbing. ## Key takeaways - Write routing rules in plain language first, then encode them as small, named middleware. - Use global middleware for locale and analytics, named middleware for auth, paid, and admin. - Run checks on the server during the first load to avoid flicker and leaks. - Keep middleware fast. Cache what you can and test failure paths. - A solid Nuxt starter kit gives you the surrounding auth, payments, i18n, and tracking so middleware stays simple. ## FAQ ### What is the difference between route middleware and server middleware in Nuxt 3? Route middleware runs before navigating to a page and is great for auth, plan checks, locale, and analytics. Server middleware runs on every server request and is better for low-level tasks like request logging or webhook signature checks. ### Where should I put Nuxt middleware files? Put route middleware in the /middleware directory. Add .global to the filename for middleware that should run on every navigation. Put server middleware in /server/middleware. ### How do I prevent infinite redirects with auth middleware? Exclude login, signup, pricing, and error pages from auth and paid checks. Also remember to pass the original destination as a query so you can return the user after login or checkout. ### Can I run async code inside middleware? Yes, but keep it minimal and cache results. For example, store plan status on login so your paid middleware does not fetch it repeatedly on every navigation. ### How do I test Nuxt middleware? Write unit tests for each middleware function and add a few end-to-end tests for critical routes. Test both success and failure paths, including expired plans and missing roles. ## Recommended resources - [practical guide to product feedback and running a feature voting board](https://feedjolt.com) # Nuxt multi-tenant SaaS architecture patterns that scale ![A practical guide to nuxt multi-tenant SaaS design. Learn viable routing, shared-DB isolation, billing, and testing patterns that scale without surprises.](https://shipahe.ad/images/blog/nuxt-multi-tenant-saas-architecture-patterns-that-scale/post-342.webp){style="max-width:100%;border-radius:12px"} Building a multi-tenant SaaS on Nuxt 3 and Nitro is a sequence of high-leverage decisions. Get tenant identity right, scope every request, enforce isolation in the database, and wire billing to entitlements. Do this early and you can ship in weeks, then scale tenants, traffic, and teams without rewrites. This guide gives concrete patterns you can implement in a new Nuxt app or layer onto an existing codebase. Each choice is framed so it is easy to ship now and safe to evolve later. ## Tenancy foundations that scale in Nuxt Multi-tenant means many customers share one application stack. You trade some isolation for speed and cost efficiency. Start simple, but design the seams so you can increase isolation as needs grow. ### Single-tenant vs multi-tenant at a glance - **Single-tenant:** One customer per stack. Maximum isolation, high cost. Choose it only when contracts or data residency make it mandatory. - **Multi-tenant:** Many customers on one stack. Lower cost, more complexity. The default for most early-stage Nuxt apps. ### Tenant identity drives everything - Create a first-class `tenants` table with `id` (UUID), `slug`, `plan`, `status`, `trial_ends_at`, and timestamps. - Model membership with a join table like `tenant_users` holding `tenant_id`, `user_id`, and `role` (owner, admin, member, viewer). - Every tenant-owned record carries `tenant_id`. Keep truly global tables separate. - Expose tenant context in both the client (a composable) and the server (request-scoped object) so every layer can enforce it. ### Isolation levels you can evolve through - **Row-level in a shared database:** Single Postgres instance, tables carry `tenant_id`. Use composite unique indexes like `(tenant_id, slug)`. Consider Row Level Security policies to enforce scoping in the database. This is the fastest path to production. - **Schema-per-tenant:** Still one database server, each tenant has its own schema. Stronger blast radius control but more migrations and connection juggling. - **Database-per-tenant:** Highest isolation short of single-tenant. Operationally heavy. Adopt for regulated customers or very large tenants. ## Routing and request scoping Your routing model sets cookie scope, perceived brand quality, and how easy observability will be. Choose once, then apply it consistently across SSR, server routes, and static assets. ### Subdomain per tenant Pattern: `acme.example.com`. Parse the host in a Nitro server middleware, resolve the tenant by `slug`, and attach it to the event context. Benefits: clean session separation, analytics by host, and straightforward custom-domain support later. For custom domains, verify DNS ownership on onboarding, store the mapping, and let your edge terminate TLS per host. Keep cookie domains scoped to the subdomain so tenants cannot see each other’s sessions. ### Path-based tenancy Pattern: `/t/acme/...`. Resolve the slug from the path and fetch the tenant in a route middleware. It is easy to host anywhere and avoids wildcard DNS. Be strict about internal links always including the tenant segment to prevent cross-tenant navigation. Favor absolute paths that include the resolved slug. ### Tenant-aware middleware in Nuxt - Create a small server middleware that resolves `tenant` from host or path and fails closed if not found. - Expose a `useTenant()` composable that reads the server-provided context on SSR and hydrates a client store. Do not let components guess. - Order of operations: resolve tenant, then locale. Keep the i18n switch tenant-aware so language changes never drop the tenant prefix. - Protect caching: add a Surrogate-Key or Vary header that includes `tenant_id` so edge caches and CDNs cannot bleed content across tenants. ## Data isolation and storage Start with a shared Postgres database and row-level scoping. Treat `tenant_id` as non-negotiable and enforce it at the ORM and database levels. ### Modeling and constraints - Add `tenant_id` to every multi-tenant table. Use composite unique keys for namespaced uniqueness, for example `(tenant_id, email)` or `(tenant_id, slug)`. - Prefer foreign keys that include `tenant_id` to stop cross-tenant references. A common pattern is a composite FK on `(id, tenant_id)` pairs. - Use a typed ORM and repositories that always require `tenant_id`. Ban queries that accept only a primary key. Add helpers that auto-stamp `tenant_id` on inserts. - Design for soft deletes with `deleted_at`. Add partial indexes to keep lookups fast while ignoring deleted rows. ### Files and storage - Use S3-compatible storage with a prefix like `tenants/{tenant_id}/...`. Never store tenant-owned files at the root. - Keep file metadata in the database with `tenant_id`, size, checksum, and content type. Validate metadata before issuing a download. - Serve uploads with short-lived presigned URLs and enforce content disposition to avoid leaking file names. - Apply lifecycle policies per prefix to expire archives and comply with retention rules. ### Scheduled jobs and background work - Drive cron tasks by iterating tenants in small batches and passing `tenant_id` into each job payload. Keep jobs idempotent with an idempotency key per tenant and day. - Bound retries and isolate noisy tenants by limiting concurrency per tenant. A single failing job must not block the global queue. - For long-running work like exports or AI generation, store progress rows keyed by `tenant_id` so the UI can poll safely. ## Billing and lifecycle controls Without billing, tenancy is a hobby. Bind access to a subscription or one-time purchase and express plan rules as enforceable checks at the server boundary. ### Checkout, entitlements, and limits - Bind subscriptions to `tenant_id`, not users. A user can belong to multiple tenants with different roles and plans. - Express plan rules in code and data. A simple `entitlements` table with keys like `max_users`, `max_projects`, `ai_tokens_per_month`, and `file_storage_mb` makes checks simple and auditable. - On successful checkout, upsert the subscription, store the current period, and emit a domain event so the app can enable features and send emails. ### Trials, seats, and usage-based features - Track seat counts on the tenant. Enforce limits in the invite flow and surface an upgrade CTA if the cap is reached. - Handle past-due gracefully. Keep access to data, restrict premium features, and schedule retries. End with a clear downgrade state if payment fails. - For AI tools and content generation, meter usage per tenant. Count tokens, requests, or images, store them with `tenant_id` and billing period, and cap or throttle when the entitlement is exhausted. ### Admin controls - Provide a staff-only Admin Panel to view tenants, users, subscriptions, and recent events. - Require elevated roles for dangerous actions like bans and refunds. Log who did what and when for every mutation. - Allow safe user impersonation for support with a visible banner and automatic revert, recording an audit entry. ## Testing and observability by tenant Multi-tenant bugs hide in edges and defaults. Make tests and telemetry tenant-aware from day one. ### Automated tests that assert isolation - Seed at least two tenants in fixtures and run every read and write twice: Tenant A cannot see Tenant B. - Write end-to-end flows for signup, invite, checkout, upgrade, and downgrade. Tools like FlyTrap help explore flows and generate tests that surface cross-tenant navigation errors. - Add smoke tests that verify middleware blocks requests without a resolved tenant. ### Feature flags and migrations - Roll out risky features to a subset of tenants. Keep the flag check on the server so it cannot be bypassed by the client. - Rehearse migrations on a staging snapshot. Include backfills that are idempotent and safe to retry under load. - Instrument each migration with timing and row counts per tenant so you can spot outliers before they hit production. ### Logs, metrics, and analytics - Attach `tenant_id` to every log line, trace, and metric. Include the user id and request id for correlation. - Track per-tenant pageviews, signups, invites, and billable events. Use these to plan capacity and discover churn risks. - Alert on error rates and latency by tenant so a noisy customer cannot hide global issues, and a global incident is obvious. Want to ship faster without rebuilding basics? A Nuxt SaaS starter kit gives you authentication, protected pages, a typed database with an ORM, i18n with an in-app language switch, an Admin Panel, scheduled jobs, and ready-to-wire one-time or subscription payments keyed to `tenant_id`. Shipahe.ad packages these into a Nuxt boilerplate with deployment tooling so you can focus on plan limits, data modeling, and the features that make your product valuable. ## Key takeaways - Decide tenant identity first and expose it in middleware, composables, and the database. Everything hangs on `tenant_id`. - Start with a shared Postgres database and row-level scoping. Evolve to schema or database per tenant only when contracts or scale demand it. - Pick one routing model and enforce tenant context everywhere. Cache and cookies must be tenant-aware. - Tie subscriptions to tenants and enforce entitlements in server routes. Be generous with data access during billing issues. - Test isolation continuously and stamp `tenant_id` on logs, traces, and metrics. Observability makes support and scaling sane. # Nuxt SaaS case study: launching an MVP in 10 days ![How we shipped a paid AI MVP in 10 days with a Nuxt starter kit. Real metrics on traffic, signups, conversions, revenue, and the exact features we used.](https://shipahe.ad/images/blog/nuxt-saas-case-study-launching-an-mvp-in-just-10-days/post-296.webp){style="max-width:100%;border-radius:12px"} You do not need a big team to ship a credible SaaS. You need a tight scope, a stack that removes decisions, and a plan to prove demand before energy runs out. This Nuxt SaaS case study shows how we shipped a paid AI MVP in 10 days, collected real revenue in 14 days, and avoided writing the parts every app repeats. ## Goals, constraints, and scope The brief: build a micro SaaS that turns messy customer notes into clean summaries with optional image snippets. We imposed two hard constraints. Timebox to 10 calendar days from repo to first paid user. Prove traction with numbers, not a demo. Launch targets for the first two weeks: - 1,000 unique visitors - 200 account signups - 25 paid conversions Scope pressure was real. We needed authentication, payments and checkout, an Admin Panel, analytics, SEO defaults, file uploads, multi-language support, and AI text plus image generation. Building that stack from scratch would consume the entire timeline. The guiding question became: how do I build and sell an AI tool online without rebuilding plumbing? Acceptance criteria were practical. First win under 5 minutes from signup. One pricing page. One onboarding flow. No custom design systems. No experimental features unless they directly lifted activation or conversion. ## Why a Nuxt starter kit and what we used We chose a Nuxt starter kit because server-rendered Vue with file-based routing and first-class content tooling fits the shape of a small SaaS. SSR gave us fast first paint and crawlable pages. Vue single-file components kept velocity high. Content collections made it easy to ship a landing page and one helpful post. We picked Shipahe.ad’s Nuxt boilerplate to avoid undifferentiated work. Out of the box we used: - User Authentication with email and Google. Sessions, password reset, and magic links were prebuilt with transactional email templates. - Payments and checkout for subscriptions and one-time credits. Success states and webhooks were scaffolded, so our work was pricing, copy, and testing. - An Admin Panel to view users, filter by plan or activity, and ban abusive accounts. Access control was already wired. - Multi-language support with an in-app language switch. Locale persisted per user and in URLs for SEO. - A type-safe database layer and migrations, plus S3-compatible file storage with signed URLs for uploads and downloads. - AI Generation Tools that let us call chat, text, and image models with a provider-agnostic interface. - Built-in Analytics for pageviews, signups, and custom events. No third-party pixels. - SEO automation for titles, descriptions, Open Graph images, and a sitemap. - A prebuilt landing page and a blog powered by Nuxt Content. - Cron job scaffolding for nightly tasks like cleanup and email nudges. Two operational choices increased speed further. We paired the kit’s AI coding workflow with Cursor to scaffold components and refactor quickly. We also kept the surface area small: one core workflow, one pricing page, one onboarding checklist. ## The 10-day build, day by day ### Days 1-2: Foundation without ceremony - Project created and environment variables wired in under 30 minutes. Local and staging envs used the same keys and .env layout to prevent “works on my machine” drift. - Authentication live on day 1. Email and Google login worked out of the box. We customized email templates and added rate limiting on auth endpoints. - Admin Panel online with search, plan filters, and manual bans. No need to build admin tables, pagination, or RBAC. ### Days 3-4: Payments and pricing - Configured subscriptions and a one-time credit pack. Webhooks for invoice.paid and charge.succeeded were pre-registered, so we focused on copy and testing downgrade and retry flows. - Kept the integration provider-agnostic. We launched with one provider and preserved the option to switch later by changing a single config and a small adapter. - Added basic usage limits per plan. Free users got 3 summaries and no images. Paid users got higher limits and priority processing. ### Days 5-6: Core AI and file handling - Implemented the main feature using the AI tools. Users pasted messy notes or uploaded a text file. We returned a structured summary with headings, bullets, and action items, and optionally generated a small illustrative image. - S3-compatible storage handled attachments with 15-minute signed URLs. We validated file type and size on both client and server. - Added nightly cron jobs: purge expired uploads, recalculate usage, and send a daily digest of new summaries to opted-in users. ### Day 7: Analytics, SEO, and content - Instrumented funnel events: signup\_submitted, onboarding\_completed, first\_summary, checkout\_started, checkout\_completed, and churn\_requested. - Verified SEO automation. We set default titles and descriptions, added canonical tags, checked OG and Twitter card previews, and generated the sitemap. - Shipped the landing page with focused copy and a single tutorial post to answer “who is this for” and “what does a good input look like.” ### Days 8-9: i18n, onboarding, and polish - Enabled English and Spanish with keyed UI strings. Locale choice persisted per user and in links for sharing. - Built a three-step onboarding checklist: upload a sample file, run a summary, and choose a plan. Admin shortcuts let support unblock stuck users fast. - Finalized transactional emails for welcome, password reset, and invoices. We kept them short, with plain language and a single next action. ### Day 10: Launch - Soft-launched to a small list and two communities. No discounts. We led with a 20-second screen recording that showed the first-win path. - Published a short changelog and opened a public feedback board. For prioritization, tools like Feedjolt help teams de-duplicate requests and decide what to build next without guesswork. ## Results: traffic, revenue, and ops ### Traffic and funnel - First 7 days after launch: 1,286 unique visitors. - Signups: 231 accounts created. Signup rate 17.9 percent of visitors. - Onboarding completion: 184 users ran at least one summary. Activation rate 79.6 percent of signups. - Paid conversions in 14 days: 31 new customers. Visitor-to-paid rate 2.4 percent. ### Revenue - Subscription plan plus a one-time credit pack. Revenue in the first 14 days totaled 1,480 USD. - 62 percent of revenue from subscriptions. 38 percent from one-time purchases. Refund rate 0 percent in the period. ### Ops and support - Average first-response time to support emails: 2 hours. Admin Panel shortcuts for user lookups and bans cut triage to minutes. - Nightly cron jobs sent an activation nudge to inactive signups. That email lifted day-2 activation by 11 percent. - Infra remained simple. One app cluster, object storage for uploads, and a single database. No service sprawl, no custom queues. ## Where the time actually went The kit removed whole categories of work. Here is what we would have spent building from scratch, compared to what we actually spent customizing the provided modules. - User Authentication. From-scratch estimate 2-3 days. Actual 0.5 day to style, configure providers, and add rate limits. - Payments and checkout. From-scratch estimate 3-4 days. Actual 1 day for pricing, copy, and flow tests including downgrades and failed renewals. - Admin Panel. From-scratch estimate 1-2 days. Actual 0.5 day to add search filters and quick actions. - File storage. From-scratch estimate 1 day. Actual 0.25 day to add validations and signed URL TTLs. - AI integration. From-scratch estimate 2 days to wire models and prompts. Actual 1 day to tune prompts and sanitize outputs. - Analytics. From-scratch estimate 0.5 day. Actual 0.1 day to confirm events and dashboards. - SEO. From-scratch estimate 0.5 day. Actual 0.1 day to validate tags and social previews. - i18n. From-scratch estimate 1 day. Actual 0.5 day to translate strings and test locale persistence. - Transactional emails. From-scratch estimate 1 day. Actual 0.25 day to edit templates and send tests. Conservatively, that is 10 to 14 engineering days saved. We reinvested those days in UX writing, pricing tests, and onboarding, which is where early traction usually lives. ## Lessons and a repeatable playbook ### What worked - Ship the boring parts pre-baked. Authentication, payments, admin, analytics, and SEO are not your edge. A Nuxt starter kit lets you spend time on the experience customers notice. - Own the funnel with built-in visibility. Instrument events at the app layer. Our biggest lift came from an activation nudge via cron and clearer upgrade copy. - Scope like a hawk. We cut anything that did not help a user succeed on day 1. One post, one page, one workflow. - Keep switching costs low. Provider-agnostic payments and swappable AI models protect you from fees or quality shifts later. - Content compounds. One tutorial that answered frequent questions now brings steady, qualified traffic for long-tail Nuxt SaaS queries. ### How to replicate in 10 days - Day 0: Write acceptance criteria. Define the first win, the single pricing page, and the activation event you will measure. - Day 1-2: Stand up auth and an Admin Panel. Add rate limits and support shortcuts early. - Day 3-4: Configure payments. Test success, failure, retries, upgrades, and downgrades. - Day 5-6: Build the core workflow end to end. Add minimal validation and guardrails. - Day 7: Instrument analytics, finalize SEO, and publish one helpful post. - Day 8-9: Add i18n for one secondary locale and a simple onboarding checklist. - Day 10: Launch to a targeted list. Collect feedback and ship one improvement per day. ### Key takeaways - A focused Nuxt starter kit can save 10 or more engineering days on an MVP. - Use built-in auth, payments, an Admin Panel, analytics, SEO, and file storage to keep your team on core value. - AI tools and model flexibility let you ship an AI MVP that feels complete on day 1. - Measure the funnel from the start and automate nudges with cron jobs. - Ask a simple question: what moves someone from first run to first win in under five minutes? If you are weighing a Nuxt boilerplate or a Vue Nuxt starter template and want to ship fast, treat this as your checklist. Pick the smallest surface that can make money, choose a Nuxt boilerplate that includes the boring parts, and invest your energy where it counts. # Nuxt SEO Best Practices – How to Get Your SaaS Ranked in 2026 You can build the best SaaS in the world, but if you're invisible on Google, you don't have a business. For solo founders, organic traffic is the ultimate leverage. It’s consistent, high-converting, and—most importantly—free. Nuxt is already a beast for SEO thanks to Server-Side Rendering (SSR). But out-of-the-box performance isn't enough to beat the competition in 2026. Here is the exact SEO checklist I use for every Nuxt project to ensure it actually ranks. --- ## 1. Dynamic Metadata Management Google uses your Page Title and Meta Description to understand what your page is about. If these are missing or generic, you won't rank. In Nuxt, you should use the `useHead` or `useSeoMeta` composable. **The Golden Rules for Metadata:** - **Title:** Under 60 characters. Place your primary keyword at the beginning. - **Description:** Under 155 characters. Include a call to action (e.g., "Try for free"). ```typescript useSeoMeta({ title: 'Optimize Your SaaS for SEO in 5 Minutes | ShipAhead', ogTitle: 'Optimize Your SaaS for SEO in 5 Minutes', description: 'Learn the exact Nuxt SEO best practices used by successful founders to reach page one of Google.', ogDescription: 'Learn the exact Nuxt SEO best practices used by successful founders to reach page one of Google.', ogImage: 'https://shipahe.ad/og-image.png', twitterCard: 'summary_large_image', }); ``` --- ## 2. Structural Hierarchy (H1 to H6) Google's crawlers read your page like a book. Your H1 tag is the book title. Every page must have exactly **one** H1 tag that contains your main keyword. **Bad Heading:** "Our Platform Helps You Build" (Vague) **Good Heading:** "Build and Launch Your SaaS in 7 Days" (Benefit-driven and keyword-rich) Use H2 and H3 tags to break up your content into logical sections. This makes it easier for both Google and humans to skim your site. --- ## 3. Automated Sitemaps and Robots.txt You want to make it as easy as possible for Google to find every corner of your site. - **Sitemap:** Use the `@nuxtjs/sitemap` module. It automatically generates a list of all your pages so Google never misses an update. - **Clean URLs:** Ensure your slugs are descriptive. For example, `/blog/nuxt-seo-best-practices` is much more valuable than `/post/12345`. --- ## 4. Boost Ranking with Structured Data (JSON-LD) Structured data tells Google specifically what kind of content you have. For a SaaS, you should use "SoftwareApplication" schema. This can lead to "rich snippets" in search results, like showing your pricing or star ratings directly on the Google search page. --- ## 5. Prioritize Page Speed (Core Web Vitals) Google explicitly ranks faster sites higher. **Search engine optimization for startups** often starts with performance. - **Optimize Images:** Use the `nuxt-img` component to serve WebP images that are 80% smaller than JPEGs. - **Server-Side Rendering:** Always use `ssr: true` (the default) to ensure Google can see your content immediately without waiting for JavaScript to load. By starting with a foundation like [ShipAhead](https://shipahe.ad){rel=""nofollow""}, you get these performance optimizations out of the box. --- ## 6. Internal Linking Strategy Don't let your pages be "islands." If you write a blog post, link back to your home page and your features page. This "spreads the juice" and helps Google understand which pages are the most important. --- ## 7. The Power of Content Marketing The best way to get traffic is to provide value. Start a blog and answer the questions your customers are asking. If someone searches for "How to take payments in Nuxt" and finds your guide, they are 10x more likely to buy your Nuxt starter kit. This is the secret to sustainable, long-term growth. --- ## Final Thoughts SEO is a marathon, not a sprint. By implementing these **Nuxt SEO best practices**, you are building an asset that will bring you customers for years to come. Ready to build an SEO-optimized SaaS? Get [ShipAhead](https://shipahe.ad){rel=""nofollow""} and hit the ground running with a search-ready foundation. # Nuxt Stripe payments for one-time and subscription billing ![Set up Stripe payments in Nuxt: one-time checkout, subscriptions, trials, webhooks, testing, and launch steps with concrete examples you can ship today.](https://shipahe.ad/images/blog/nuxt-stripe-payments-for-one-time-and-subscription-billing/post-496.webp){style="max-width:100%;border-radius:12px"} You want to accept money in your Nuxt app without duct-taping code together. Stripe is a solid choice, but mixing one-time purchases, subscriptions, trials, and the webhook glue gets confusing fast. This guide gives you a clear, repeatable pattern for Nuxt Stripe payments that you can put in production. We will use Stripe Checkout because it is quick to implement, handles Strong Customer Authentication, and works for both one-time and recurring billing. The same structure applies whether you are selling a small digital product, an AI tool, or a full SaaS. ## 1) Choose your payment flow ### Pick a product model - One-time purchase. A single payment that unlocks a file, feature, or credit pack. Good for add-ons and downloadable assets. - Subscription. Recurring billing tied to plans. Add free trials or intro pricing if needed. Good for SaaS tiers and usage that resets monthly. - Hybrid. Mix both. For example, a monthly plan plus a one-time add-on that boosts limits. If you are building something like CoinDrop, you might sell a monthly tier and let users buy a one-time boost for a promotion. ### Choose Stripe primitives - Define Products and Prices in the Stripe Dashboard. Use one-time prices for single charges and recurring prices for subscriptions. - Use Stripe Checkout for the hosted payment page. Always create the Checkout Session on your server and redirect the browser to it. This keeps PCI scope low and handles 3D Secure. - Use Webhooks to confirm payment and flip access in your app. Do not grant entitlements on a client-only success page. - Create a Stripe Customer for each user and store customer\_id on your User row. That makes upgrades, refunds, and future purchases consistent. ## 2) One-time payments with Stripe Checkout Your flow: user clicks Buy, your server creates a Checkout Session with mode set to payment, Stripe collects the card, Stripe pings your webhook, and your app grants access. 1. **Define the catalog.** In Stripe, create a Product with a one-time Price. Record the price\_id in your app config. Keep an allowlist of valid price ids on the server. 2. **Server route to create a session.** In Nuxt 3, add a POST route like /api/checkout that validates input, attaches user metadata, and returns session.url. Include success and cancel URLs that route back to your app. ``` ``` 3. **Redirect from the client.** On your product page, call /api/checkout and redirect to the returned URL. Keep the UI clean. One Buy button, a short explainer, and a price. 4. **Flip access on webhook, not on the success page.** In your webhook handler, verify the signature and on checkout.session.completed mark the purchase as paid. Create a Purchase row that includes payment\_intent id, user\_id from metadata, and the product key. Grant access by inserting a record into a UserEntitlements table or toggling a feature flag. ``` ``` 5. **Send receipts.** Stripe can send receipts automatically. If you send your own email, include a link to the protected page or download, and a VAT invoice link if you collect tax IDs. 6. **Protect the content.** Gate access server-side. For downloads, generate a short-lived signed URL after you confirm the paid Purchase record. ## 3) Subscriptions and trials Subscriptions add lifecycle events. Plan for upgrades, downgrades, renewals, cancellations, and expired trials. Stripe Checkout creates the subscription and emits consistent events you can trust. 1. **Create recurring prices.** In Stripe, set up monthly or yearly Prices. If you want a trial, either set a trial period on the Price or set trial\_end when creating the Checkout Session to control the exact date. 2. **Subscription checkout route.** Similar to one-time, but set mode to subscription and pass the recurring price id. Keep a server-side allowlist of tier price ids, and add user\_id and plan to metadata. ``` ``` 3. **Persist the subscription.** On checkout.session.completed, read session.subscription to get the subscription id. Store a Subscription row with status active, current\_period\_end, plan id, and the Stripe customer id. Use invoice.paid to extend access and invoice.payment\_failed to start dunning with a short grace period. 4. **Upgrades and downgrades.** For upgrades mid-cycle, update the subscription item with proration\_behavior set to create\_prorations so users pay the difference. For downgrades, schedule the change at period end and reflect it in your UI with a plan\_change\_requested flag. 5. **Cancellations and trials.** On customer.subscription.updated or deleted, sync status to past\_due, canceled, or paused. If a trial ends without payment, remove entitlements when the subscription becomes incomplete\_expired. ## 4) Webhooks, testing, and launch ### Webhook fundamentals - **Verify signatures.** Use the signing secret from your Stripe Dashboard. Reject any event that fails verification. - **Idempotency and retries.** Store processed event ids. Stripe retries on failures and timeouts. Make handlers side-effect safe. - **Map events to users.** Put your internal user\_id into Checkout Session metadata or into the Customer object. Do not rely on email lookups that can change. - **Choose the right events.** For one-time, rely on checkout.session.completed. For subscriptions, also listen to invoice.paid, invoice.payment\_failed, customer.subscription.updated, and customer.subscription.deleted. Handle charge.refunded to revoke one-time access when needed. ### Receipts and emails - **Stripe receipts.** Turn on email receipts in Stripe for payment confirmations and refunds. - **Your transactional emails.** Send welcomes, payment confirmations, dunning messages, and cancellation notices from your app. Include a Manage billing link in your account area. ### Testing - **Use test keys and env vars.** Keep STRIPE\_SECRET\_KEY and STRIPE\_WEBHOOK\_SECRET in .env. Never mix test and live data. - **Test 3D Secure and failures.** Use Stripe’s test cards to cover success, authentication required, insufficient funds, and generic declines. Verify your UI messages. - **Run webhooks locally.** Use the Stripe CLI to forward events to your machine: stripe listen --forward-to localhost:3000/api/stripe-webhook. Replay an event to confirm idempotency. - **Validate entitlements.** After each test purchase, check database rows and confirm protected pages are gated. Revoke access and test again to catch race conditions. - **Refunds and disputes.** Add a simple admin action to refund and revoke access. For subscriptions, document whether you prorate on mid-cycle refunds. - **Go live safely.** Switch production to live keys, set the live webhook signing secret, and verify success\_url and cancel\_url use your live domain. Run a small live charge on your own card to sanity check. ### Where a Nuxt SaaS starter kit helps If you want to ship fast, a solid Nuxt SaaS starter kit cuts weeks from setup. Shipahe.ad includes authentication, protected pages for paid features, subscription and one-time checkout flows, webhooks wired to entitlements, transactional emails, an admin panel to view users and ban spammers, multi-language support with an in-app switch, deployment presets, a prebuilt landing page you can customize, built-in analytics to watch signups and conversions, and SEO automation for meta tags and sitemaps. It also works cleanly with AI coding tools like Cursor or Claude, which helps you write server routes and handlers faster without fighting the stack. ## Key takeaways - Stripe Checkout plus webhooks is the fastest, reliable path for Nuxt Stripe payments across one-time and subscriptions. - Model entitlements in your database and flip them only on verified webhook events, not on client redirects. - Keep a Stripe customer\_id on each user and an allowlist of price ids on the server. - Test every branch in test mode, including authentication-required flows and failures, before going live. - A Nuxt starter kit with payments, protected pages, emails, and admin removes setup friction so you can focus on your product. # Nuxt vs Vue: How to Choose, Set Up, and Ship Fast Today ![Nuxt vs Vue with concrete steps, quickstarts, SSR gotchas to avoid, and how a Nuxt SaaS starter kit helps you launch paid features and rank faster.](https://shipahe.ad/images/blog/nuxt-vs-vue-how-to-choose-set-up-and-ship-fast-today/post-715.webp){style="max-width:100%;border-radius:12px"} You want your first paid users, not a month of wiring. The Nuxt vs Vue choice decides how many decisions you make later and how fast you get to a protected, paid slice. Here is a clear way to choose, set up both, and avoid the traps that slow down SaaS launches. ## What Nuxt vs Vue actually means Vue is the UI layer. It gives you components, reactivity, and a client-side app by default. You assemble routing, state, meta tags, data fetching, and any server piece yourself. That flexibility is great for small SPAs and embed widgets, but it means more glue when you need SEO, auth, and payments. Nuxt is a full-stack framework built on Vue. It adds file-based routing, a server runtime via Nitro, first-class SSR and static generation, server routes in *server/api*, auto-imported composables, meta and SEO helpers, and an opinionated structure. You can pick rendering per route, share types between client and server, and deploy to Node or serverless. For SaaS work where you need public pages that rank and an authenticated app that just works, Nuxt removes a lot of decisions. In practice: choose Vue for a small SPA or widget where SEO does not matter and a static host is enough. Choose Nuxt when you need marketing pages to index, fast first paint, server endpoints for auth, webhooks, and payments, or a predictable structure for a growing app. ## How to decide in 5 concrete steps 1. **List non-negotiables.** Write down must-haves for v1. Common SaaS needs: public landing and pricing pages, user dashboard, authentication, protected routes, subscription billing, multi-language, transactional email, analytics, file uploads, cron jobs, and maybe an AI chat or generator. If public pages need to be fast and indexable on day one, lean Nuxt. 2. **Pick a rendering model per page type.** Map pages to rendering early. Examples: */*, */pricing*, */blog* as SSR or static; */app* dashboards as client-first; */docs* as static with incremental rebuilds. With Vue alone you stay client-only unless you bolt on SSR or SSG. With Nuxt you can mix SSR, SSG, and client-only per route without extra tooling. 3. **Decide how much glue code you want.** Vue means choosing and wiring `vue-router`, state (often Pinia), a head manager, an HTTP layer, and an SSR or SSG approach if you need SEO. Nuxt ships file-based routes, Pinia integration, `useHead`, `useFetch`/`useAsyncData`, runtime config, and server routes. If the goal is a working paid slice this week, Nuxt reduces integrations and edge-case bugs. 4. **Plan hosting and deployment.** Pure Vue SPAs work on any static host. Nuxt 3 apps can deploy to Node servers or serverless. Check your provider supports Node 18+ and the Nuxt server runtime. If you need server routes for webhooks or payments, Nuxt’s *server* directory keeps everything in one repo. 5. **Timebox a spike in both.** Spin up a Vue project and a Nuxt project. Implement one public page with a meta description, one protected route, and a mock subscription check. Ship whichever stack gets you there cleaner and faster. ## Quickstart: set up Nuxt and Vue side by side ### Nuxt quickstart 1. **Create the project.** ``` ``` 2. **Add a page.** Create *pages/index.vue*. Nuxt routes it automatically. ``` ``` :br 3. **Create a server route.** Add *server/api/ping.get.ts* for a simple health check. ``` ``` 4. **Fetch data safely.** Use `useAsyncData` to call your API with SSR support. ``` ``` :br 5. **Choose rendering per route.** Mark pages client-only or pre-rendered. ``` ``` ``` ``` 6. **Guard analytics and browser-only code.** Put browser-only plugins in *plugins/analytics.client.ts* so they never run on the server. Wrap window access in client checks or the built-in component below. ``` ``` ### Vue quickstart 1. **Create the project.** ``` ``` 2. **Add routing.** Install and configure Vue Router. ``` ``` ``` ``` :br 3. **Set document titles.** Use a head manager or set titles in `onMounted`. Full SEO requires SSR or prerendering through an additional tool. Without that, new sites often see weak indexing. 4. **Add a protected view.** Gate routes with a navigation guard that checks auth, then wire a backend or serverless functions for login and APIs. ``` ``` ## Ship faster with a Nuxt SaaS starter kit If your goal is to make your first dollars online, a production-ready Nuxt SaaS starter kit trades setup work for product work. A solid kit typically ships with: - Authentication: email and password, magic links, social sign-in, session handling on server routes, and secure cookies. - Payments: subscription and one-time charges, webhook processors, subscription state synced to your database, and a billing portal link. - Internationalization: locale switcher, per-locale routes like */en* and */fr*, message loading rules, and SEO-safe defaults. - Transactional email: password resets, welcomes, receipts, and templating with environment-based providers. - Admin: user list, role management, ban and unban, and audit logs. - Content: a blog or docs with Markdown, slugs, sitemaps, and Open Graph images. - Developer experience: a typed codebase, ESLint, formatting, unit and e2e tests, environment switch, and example CI. - File uploads: S3-compatible direct uploads with signed URLs, image processing hooks, and storage keys saved in the database. - AI features: chat and text generation wired to a provider, with model swapping in config. Buying a Nuxt boilerplate is not skipping learning. It is concentrating your time on differentiating features. If you want to buy a Nuxt boilerplate or a Vue Nuxt starter template, pick one that matches your payment provider, database, and auth model so you do not fight the foundation later. ## Common pitfalls and how to avoid them - **Mismatched rendering.** Hydration errors like "Text content does not match" happen when a component relies on `window` or browser-only APIs during SSR. In Nuxt, wrap browser-only code with `` or guard with `if (process.client)`. In Vue SPAs, avoid expecting SSR-like SEO without adding SSR or SSG. - **SEO expectations.** A pure SPA depends on client-side rendering, which new sites see indexed inconsistently. If organic traffic matters in month one, use Nuxt with SSR or static generation for public pages. To keep content flowing, consider an external helper like RankGoat for posting blogs, earning dofollow links, and fixing indexing issues. - **Auth on the server.**Do not trust client-only checks. Validate sessions in server routes and return 401 on data APIs. ``` ``` - **Payments and webhooks.** Subscription state lives on the server. Process webhooks on a server route, verify signatures, and update your database. In Nuxt, place this in *server/api/webhooks/payment.post.ts*. For Vue SPAs, use serverless functions or a small Node service. - **Internationalization sprawl.** Decide URL strategy early, such as */en* and */fr*. Centralize messages and naming, and set a default locale and fallback to avoid 404s on missing translations. - **Analytics duplication.** With SSR, ensure analytics runs only in the browser and only once. In Nuxt, put it in *plugins/analytics.client.ts* and avoid triggering it during SSR navigation. - **Cold starts and server limits.** On serverless, heavy SSR routes can suffer cold starts. Pre-render static pages and reserve SSR for pages that need user-specific data. - **File uploads.** Never upload directly to your app server in production. Use signed URLs for S3-compatible storage and store only object keys in your database. ## Key takeaways - Use Vue for small SPAs and widgets. Use Nuxt when you need SEO, speed, and a full-stack foundation. - Decide rendering per route. Pre-render marketing pages and keep dashboards client-first. - Timebox a proof in both stacks. The faster path to a protected, paid slice wins. - A Nuxt SaaS starter kit removes weeks of auth, payments, i18n, emails, content, and SEO setup. - Avoid common pitfalls by guarding browser-only code, handling auth on the server, and pre-rendering public pages. ## FAQ ### When should I choose Nuxt over Vue? Choose Nuxt when you need SEO-friendly public pages, faster first load, built-in routing and server APIs, or a clear structure for a growing SaaS. ### Can I start with Vue and switch to Nuxt later? Yes, but expect a refactor. Routing, meta handling, and data fetching patterns differ. If SEO or SSR is likely, start with Nuxt. ### Is a Nuxt SaaS starter kit worth it for a first launch? If you need auth, payments, i18n, emails, analytics, and a blog, a good starter kit can save weeks and reduce integration bugs. ### How do I make a Vue SPA SEO-friendly? Add an SSR layer or pre-render static pages. Without server rendering, search bots may index slower or miss content loaded after hydration. ### How do I handle payments in Nuxt? Use a supported payment provider for checkout and process webhooks in Nuxt server routes to update subscription status securely. # Open source Nuxt starter alternatives and when to buy ![Build, fork, or buy a Nuxt starter? See concrete trade-offs, real costs, and a simple decision map to ship a SaaS or AI app fast without weeks of glue work.](https://shipahe.ad/images/blog/open-source-nuxt-starter-alternatives-and-when-to-buy/post-464.webp){style="max-width:100%;border-radius:12px"} You want to ship a Nuxt app fast without vanishing into weeks of plumbing. You are comparing free starters, forks, and paid kits, and trying to see the real work each path hides. Here is a practical way to choose and avoid expensive rework. Even a small tool like Jigsaw Station feels simple until you add signups, paid tiers, and email, then every seam in the stack starts to matter. ## Alternative 1: Build your own Nuxt stack with modules **Strengths.** Full control and a clean mental model. You pick each piece and keep only what you need. Typical choices include: - Auth with a session or JWT strategy, OAuth providers, and magic links - Postgres or MySQL with Prisma, plus typed schema and migrations - File uploads to S3-compatible storage with signed URLs - Transactional email via a provider like Postmark or Resend - i18n with route-based locales and an in-app switcher - Analytics with a privacy-friendly tracker or self-hosted suite - SEO using useHead or a sitemap and OG image module - Background jobs via Nitro cron, a queue, or an external scheduler **Trade-offs.** You own the glue and the edge cases. Concrete pitfalls that catch teams: - **Auth on SSR.** OAuth callbacks, cookie flags, and CSRF handling differ between server routes and client navigation. Protecting server-rendered pages requires guards at both the route and API levels. - **Payments and webhooks.** Idempotency keys, proration, retries, and out-of-order webhook delivery are easy to miss. You need tests to prove subscription state cannot drift. - **Uploads and access control.** Signed URLs must expire and be scoped. Public buckets leak. Private buckets break if clock skew or region mismatches slip in. - **i18n and SEO.** Locale prefixes, canonical tags, and default language redirects must agree, or you get duplicate content and broken links. - **Edge deployments.** Some Node APIs are not available on edge runtimes. Know what runs where before you pick a host. - **Configuration drift.** ENV naming, secrets per environment, and a repeatable local setup script save hours later. Without them, onboarding slows to a crawl. Even seasoned developers underestimate the time to harden auth, nail webhook flows, and close file access holes. A two week plan turns into two months when you hit production-only bugs. ## Alternative 2: Fork an open source Nuxt SaaS template **Strengths.** You start close to done. Many templates include a layout, a landing page, and basic auth. Swap the branding and deploy. For hackathons, a demo for a client, or a class project, it is the fastest way to show a working app. **Trade-offs.** You inherit someone else’s decisions and backlog. Maintainers do not owe you fixes. Before you commit, verify in your own environment: - **Auth really protects data.** Try private pages without a session, test magic links and social providers, and reload SSR pages to catch hydration gaps. - **Payments complete and persist.** Run both one-time and subscription flows with test cards, kill the network mid-flow, then confirm state via the dashboard and your database. - **Admin is usable.** Can you search users, ban spam accounts, and undo mistakes with audit trails or soft deletes. - **Database is safe to evolve.** Typed models, repeatable migrations, and seed data reduce risk during refactors. - **Uploads and emails work end to end.** Confirm signed URLs, attachment sizes, and production SMTP settings with a real provider. - **CI, tests, and releases exist.** Look for a passing CI workflow, a recent release, and a changelog. A stale lockfile is a red flag. Most open source starters stop at demo-grade features. That is fine if your goal is to learn and extend, but budget time to harden everything before you ask users for money. ## Alternative 3: Buy a production-ready Nuxt SaaS starter kit **Strengths.** You trade a fee for a head start on the parts that usually slip. A good Nuxt SaaS boilerplate ships with guarded routes, end-to-end auth, an admin area, payments with webhooks and receipts, i18n, transactional emails, analytics, SEO, storage, and a documented deployment path. If your plan is to charge soon, this is often the shortest path to a stable baseline. Shipahe.ad offers a Nuxt starter kit built for production. It includes protected pages, authentication with email and password, magic links, and Google, an admin panel to view users and ban spammers, and checkout flows for one-time or subscription payments with multiple, swappable providers. You get multi-language support with an in-app language switch, transactional emails with pre-made templates, a prebuilt landing page you can customize by swapping text, a blog powered by Nuxt Content, built-in analytics for pageviews and signups, SEO automation for meta tags, Open Graph images, and sitemaps, a preconfigured database with an ORM and typed codebase, S3-compatible file uploads, scheduled cron jobs for reports and reminders, and AI features like chat, text, and image generation with switchable GPT models. It is also designed to work well with AI coding tools like Cursor and Claude. If you are asking How do i build and sell an ai tool online, a Nuxt SaaS starter kit like this gives you both generation features and payments on day one. **Trade-offs.** You adopt the kit’s conventions. That is the point, but it still means learning a codebase. If you want a different ORM or a custom auth stack, budget time to adapt the wiring. ## Cost, migration, and support **Time and money.** Free often costs more in hours. Conservative build times for production features in a Nuxt app: - Auth with protected routes, magic links, social sign-in: 16 to 40 hours - Payments with subscriptions, webhooks, retries, invoices: 24 to 60 hours - Transactional emails with templates and delivery: 10 to 16 hours - Multi-language UI with a language switch and routing: 8 to 20 hours - Admin area with user search, actions, and audits: 12 to 24 hours - Analytics setup and basic dashboards: 6 to 12 hours - SEO for meta, OG images, and sitemap: 6 to 10 hours - S3-compatible uploads with secure access: 12 to 24 hours - Scheduled jobs for emails and reports: 4 to 8 hours - AI chat and generation features: 16 to 40 hours At modest rates, 120 to 250 hours dwarfs the price of a paid Nuxt boilerplate. That does not include upgrades, bug fixes, or rewrites when dependencies change. **Migration path.** If you start with DIY or a forked template, isolate your domain logic so you can switch foundations later. Practical steps: - Wrap auth, payments, storage, and email in a service layer with typed interfaces so calls are easy to remap - Keep one ORM and a clean migration history so you can export and import data safely - Store secrets in a single config module, document required ENV, and script local setup - Use feature flags to replace modules in small steps, not a big bang cutover - Plan data mapping for users and subscriptions, including password hash formats and provider IDs - Run both stacks in parallel for a few days and replay webhooks to catch edge cases before flipping traffic **Support reality.** With DIY or open source, support is you and the community. With a paid kit, you get a cohesive stack, consistent patterns, and documentation that cuts onboarding time. If your roadmap moves weekly, fewer decisions add up to faster delivery. **Decision map.** - If you are learning Nuxt or exploring, build your own stack. - If you need an MVP this week, fork a template and budget time to harden it. - If you plan to charge within a month, buy a Nuxt starter and focus on product logic. - If your product is an AI tool with paid tiers, prefer a Nuxt kit that ships generation plus subscriptions on day one. - If compliance or uptime risk matters, pick the path that minimizes custom glue and unclear ownership. ## Key takeaways - Open source starters get you moving, but production features like auth, payments, i18n, admin, analytics, SEO, storage, cron, emails, and AI add up fast. - DIY gives control. Forked templates give speed. Paid Nuxt SaaS starter kits give a stable baseline and a shorter path to revenue. - Total cost of ownership often makes buying a Nuxt boilerplate cheaper within weeks, not months. - For AI products, built-in generation plus subscriptions answers How do i build and sell an ai tool online with fewer moving parts. # PaaS vs SaaS: Pick the Right Mix and Ship Your Nuxt App Fast ![Clear PaaS vs SaaS guidance for Nuxt builders, with a concrete stack, setup checklist, and pitfalls so you ship fast with auth, payments, i18n, and SEO.](https://shipahe.ad/images/blog/paas-vs-saas-choose-ship-nuxt-app-fast/post-727.webp){style="max-width:100%;border-radius:12px"} You can lose a week debating PaaS vs SaaS while your app sits. The way through is simple: decide what you must own, rent out the rest, and ship on a stack that will not box you in later. Below is a practical playbook for Nuxt teams. It explains PaaS vs SaaS in the context of a real Nuxt app, gives you a reference stack you can copy, and highlights the traps that slow launches. It reflects what actually works when your goal is to get to paid users fast without rewriting your stack in three months. ## What PaaS vs SaaS means for a Nuxt app Platform as a Service runs your code without you managing servers. You push your Nuxt app, the platform builds and serves it, handles TLS, routing, autoscaling, cron, logs, and often provides add-ons like managed databases and queues. Your application logic, server routes, and UI are yours. Software as a Service gives you a finished capability behind an API or UI. Typical uses are auth, payments, email delivery, file storage, analytics, error tracking, and search. You do not run it. You pay for usage and rely on their SLAs and security teams. Most Nuxt products do best with a mix. Put your differentiating code on a PaaS so you can move fast. Use SaaS for common building blocks you would rather not maintain. Shift that line if you have hard constraints like data residency, private networking, enterprise SSO, or strict latency budgets. ## Choose what to build vs buy - Define the core jobs. Write the 3 - 5 user jobs your product must nail. Keep that logic and the supporting data model in your codebase. Everything else is support work. - Note constraints early. List target regions, privacy rules, uptime needs, traffic shape, and team skills. If you handle PII, plan data residency. If you need private networking, check whether your PaaS supports private databases and VPC peering. - Pick your runtime shape. A Nuxt 3 starter keeps UI, server routes, and API calls together through Nitro. You get file-based routing, middleware, server/api endpoints for callbacks and webhooks, and SSR out of the box. A well-made Nuxt SaaS starter kit removes days of setup across auth, billing, admin, and SEO so you start with production rails instead of a blank page. - Decide where to buy. For a new product, buy a Nuxt boilerplate that already includes protected routes, email and Google auth, an admin area, subscriptions and one-time payments with webhooks, transactional emails, an ORM with typed migrations, S3-compatible storage, i18n with a language switcher, SEO utilities, a blog powered by Nuxt Content, cron jobs, and optional AI chat, text, and image generation modules. That checklist is boring to build and costly to get wrong. - Wire your workflows. Keep a .env.example with every required var. Use typed ORM migrations so schema changes are reviewable and safe. Seed local data so every developer can run the app in minutes. Add basic CI for type checks and linting. Ship with a staging environment and a simple smoke test that runs login, checkout, i18n toggle, and an admin action. - Launch in stages. Stand up staging on your PaaS. Run checkout with test cards. Verify email delivery and domain auth. Switch languages and confirm copy falls back correctly. Trigger webhooks and check signature verification. When it is clean, point the domain, turn on real payments, and enable analytics. ## A Nuxt SaaS reference stack and setup checklist Use this as a starting point and adjust for your needs. - Application: Nuxt 3 app using Nitro for server routes. Keep auth callbacks under /server/routes, webhooks under /server/routes/webhooks, and internal API under /server/api. Use route middleware to protect pages. Centralize feature flags and app config in runtimeConfig. - Hosting: Pick a PaaS with first-class Node support, build caching, zero-downtime deploys, cron or scheduled jobs, logs, environment variables, and rollbacks. Check websocket and server-sent events support if you stream AI responses. Understand limits like cold starts, request timeouts, and ephemeral disk. - Database: Managed PostgreSQL or MySQL. Use an ORM like Prisma or Drizzle with typed migrations. If your PaaS uses serverless functions, add a connection pooler or proxy. For zero-downtime changes, prefer additive migrations, backfill first, then swap columns. Back up before destructive changes. - Auth: Email/password, magic links, and a social login like Google cover most cases. Store sessions as httpOnly, secure cookies. Set SameSite=Lax, rotate session secrets, and expire sessions. Protect against CSRF on sensitive POST endpoints. Put role checks in server-side middleware. Keep an admin role separate from user roles and audit admin actions. - Payments: Support subscriptions and one-time credits. Map plans to immutable price IDs in code. Implement webhooks with signature verification and idempotency keys. Build a customer portal link so users can self-serve changes. Configure taxes and invoices before launch. Add usage limits in code to protect margins. - Storage: S3-compatible bucket with private ACL by default. Serve files via signed URLs that expire quickly. Set CORS for your app origins. For images, generate thumbnails in a worker so your app response stays fast. - Emails: Use a transactional provider. Authenticate your domain with SPF, DKIM, and DMARC. Keep templates versioned in your repo, not in a dashboard. Send on key events: welcomes, password reset, email verification, receipts, failed payment notices, and trial-expiry reminders. Handle bounces and complaints. - Analytics and SEO: Track signups, activations, key feature use, cancellations, and revenue-related events. Tag each event with plan and locale to spot friction. In Nuxt, set titles and meta with useHead. Generate a sitemap and robots.txt on build. Include Open Graph images for main pages and your blog. Consider a /changelog route for small updates. - Observability: Enable structured logs and save them for at least 14 days. Add uptime checks for app, API, and webhook endpoints. Alert on error rate spikes and failed checkouts. Capture unhandled rejections and log context like user ID and request ID. - Deployment: Lock Node and package versions. Cache node\_modules or use a PnP-aware installer to speed builds. Run nuxi build and a smoke test before promoting. Keep separate staging and production secrets. Prefer canary deploys for risky changes. Document a rollback. - Go-to-market workflow: Ship a basic landing page and pricing table on day one. Blog with Nuxt Content so you can publish from Markdown. If you repurpose social threads, X-Post-Copier lets you pull an X.com post with text, media, author, and links straight into your clipboard for a changelog entry or blog post. ## Pitfalls and portability tips - Reinventing auth. Login, reset flows, magic links, and session security take longer than you think. Use the boilerplate’s auth patterns and tests. - Hard-coding a single payment provider. Wrap your billing logic so you can swap later. Keep product and price IDs in config, not sprinkled in components. - Skipping i18n until later. Add a locale switch from day one, store the choice in a cookie, and keep copy in translation files so you can add languages without refactoring. - Forgetting domain auth for email. Verify SPF, DKIM, and DMARC in staging. Test password resets and receipts across providers like Gmail and Outlook. - Storing files on app disk. App instances are ephemeral. Use S3-compatible storage and signed URLs. Clean up orphaned files with a scheduled job. - Weak webhook handling. Verify signatures, use idempotency, and process in a background job to avoid timeouts. Log the raw payload securely. - No admin area. Support cannot help without visibility. Ship an admin view with user search, impersonation for debugging, spam controls, and audit logs. - Ignoring connection limits. Serverless functions can exhaust DB connections. Use pooling and keep-alive. Close clients in long-lived workers. - Over-coupling to PaaS extras. Prefer standard runtimes, env vars, and S3-compatible storage. Avoid proprietary API calls you cannot reproduce elsewhere. - Missing rate limits. Add per-user and per-IP limits on auth, file uploads, and AI endpoints. Return clear errors and surface limits in the UI. ## Ship an AI tool this week Pick one job. For example, take a folder of images and produce consistent product shots, or turn a meeting transcript into a clean summary. Wire the API to your model of choice behind a server route so you can swap models later without touching the client. Stream partial results with server-sent events for better UX and lower timeouts. Bill from day one. Offer a small credit pack for one-off use and a subscription with higher limits. Track usage in your database and stop jobs when limits are reached. Expose current usage on the billing page so customers know what to expect. Protect your margins. Add per-minute and per-user rate limits, queue long jobs, and retry with backoff on transient model errors. Log prompt inputs and token counts carefully and avoid storing sensitive user data unless you need it. Make it trustworthy. Require login for dashboards, send clear transactional emails, and show a simple audit trail of actions like uploads and generations. Watch your analytics for where users stall and fix those screens first. ## Key takeaways - Own the product-specific code on a PaaS. Rent common capabilities as SaaS so you can move faster. - A solid Nuxt starter kit shortens setup and gives you auth, payments, admin, i18n, SEO, storage, cron, analytics, and a blog on day one. - Keep portability with standard env vars, S3-compatible storage, typed migrations, and a billing layer that can swap providers. - Ship in stages with a staging app, test cards, verified email domain, webhook checks, and a smoke test you can run before every deploy. - For AI tools, start narrow, meter usage, price clearly, and stream results to improve UX and reduce failures. ## FAQ ### What is the main difference between PaaS and SaaS? PaaS runs your custom code and handles deploys, scaling, and infra. SaaS gives you a finished capability like payments or email through an API or UI. ### Which PaaS works best for a Nuxt app? Pick a PaaS that supports Node runtimes, environment variables, SSL, rollbacks, cron, and good logs. Most modern platforms that run Node will handle a Nuxt app well. ### When should I buy a Nuxt boilerplate instead of building from scratch? Buy when you need auth, payments, emails, admin, storage, analytics, SEO, and a landing page now. A starter saves weeks and reduces security and billing mistakes. ### Can I switch payment providers later? Yes, if your template separates billing logic from provider code. Choose a starter with swappable payment providers and keep webhook handling modular. ### How do I price an AI tool launched with Nuxt? Start with a low-friction monthly plan and an entry credit pack. Use analytics to see usage patterns, then tune tiers around outcomes users value. # SaaS Post-Launch Checklist – 7 Steps to a Secure Startup Clicking "deploy" is a massive milestone, but it's only the beginning. A "hardened" app is the difference between a project that survives going viral and one that crashes under the weight of its first 100 users. If you skip the post-launch audit, a simple configuration error could lead to a data breach or a broken billing flow on Day 1. This is the exact **SaaS launch checklist** I use to ensure my apps are secure, scalable, and actually ready for paying customers. --- ## Why "Hardening" Matters for Founders Most developers focus on features. Successful founders focus on infrastructure. Doing **post launch hardening** correctly helps you: - **Build User Trust:** People won't pay for an app that feels buggy or unsafe. - **Avoid Middle-of-the-Night Emergencies:** Proper monitoring saves you from waking up to a broken site. - **Scale Without Friction:** Being prepared means handling 1,000 users is as easy as handling 10. --- ## The 7-Step SaaS Launch Checklist ### 1. Audit Your Authentication Security isn't an afterthought. Ensure you are following **SaaS security best practices** by: - Enforcing strong password requirements. - Using a trusted auth provider like Better Auth. - Setting up Multi-Factor Authentication (MFA) for your own admin accounts. ### 2. Verify Your "Live" Speed Localhost is always fast, but the real world isn't. Run your live URL through PageSpeed Insights. If your mobile score is below 80, your SEO and conversion rates will suffer. ### 3. Automate Your Backups If your database disappeared tomorrow, would your business survive? **Secure your SaaS** by setting up daily, automated backups. Providers like Supabase or Turso do this with one click—make sure it is actually turned on. ### 4. Implement Error Tracking Don't wait for a user to email you a screenshot of a broken page. Use a tool like Sentry or GlitchTip. It will notify you the second a bug occurs so you can fix it before your next customer hits that same wall. ### 5. Check Your SEO Fundamentals Ensure your `robots.txt` isn't blocking Google. Verify that your sitemap is submitted to Google Search Console. A **SaaS infrastructure guide** isn't complete without making sure people can actually find your app. ### 6. The "Legal Minimum" You are dealing with user data and money. You must have: - **Terms of Service:** Protects your business. - **Privacy Policy:** Legally required (GDPR/CCPA) and builds trust. - **Cookie Consent:** Essential if you use tracking scripts. ### 7. Setup Analytics for Growth If you don't know where your users are coming from, you don't have a business. Install a privacy-first analytics tool (like Plausible or Umami) to see which pages are actually converting. --- ## Preparing Your SaaS for Scale Scaling isn't just about "bigger servers." It is about having a codebase that can be updated without breaking everything. If you started with [ShipAhead](https://shipahe.ad){rel=""nofollow""}, much of this hardening is already baked into the foundation. From secure auth to optimized page loads, we designed the boilerplate to be "launch-ready" from the first commit. --- ## Your Path Forward Don't let the excitement of launching distract you from the importance of stability. Spend 60 minutes today going through this **SaaS launch checklist**. A reliable app is a profitable app. If you haven't launched yet, get [ShipAhead](https://shipahe.ad){rel=""nofollow""} and start with a foundation that is already hardened and ready for world-class scale. # Best Nuxt Starter Kits for SaaS Projects: A Founder's Perspective Let's be real: search for "Nuxt starter kit" and you'll find a dozen repos that look great on paper but turn into a maintenance nightmare the moment you want to add a custom feature. In 2026, the game has changed. We're not just looking for "code that works." We're looking for an architecture that stays out of the way, handles the "boring" stuff (auth, billing, SEO), and—crucially—plays nice with AI coding agents. I've tried almost every **nuxt ui starter kit** and **nuxt saas starter kit** on this list. Here is my take on which one you should actually use for your next project. --- ## Why Use a Nuxt Starter Kit? What are the **benefits of using a pre-built application scaffold**? For founders and developers, the advantages are clear: - **Launch in Days, Not Weeks:** Skip the setup of authentication, stripe integrations, and database schemas. - **Production-Ready Architecture:** Most modern kits use **Nuxt 4 starter kit** patterns, ensuring your app is future-proof. - **Cost-Effective:** While some kits are paid, they are far more **affordable Nuxt starter kits** than hiring a developer to build the same infrastructure. --- ## Comparison Table: Nuxt Starter Kit 2026 Options & Alternatives | Starter Kit | Best For | Tech Stack | Key Features | Price | | :-------------------------------------------------------------------------- | :---------------------------- | :----------------------------- | :-------------------------------------------------------- | :------ | | **ShipAhead** | **Solo Founders & AI Coding** | **Nuxt 4 + Drizzle + Nuxt UI** | **Optimized for AI coding agents, AI-ready architecture** | **$99** | | [supastarter](https://supastarter.dev){rel=""nofollow""} | Enterprise Teams | Nuxt 4 + Prisma | Multi-tenancy, RBAC, I18n | $349+ | | [Nuxt Beyond](https://nuxtbeyond.com/){rel=""nofollow""} | Full-stack Web Apps | Nuxt 4 + Prisma | Robust boilerplate, good documentation | $59+ | | [Nuxt SaaS Kit](https://nuxtsaas.com){rel=""nofollow""} | Content-heavy SaaS | Nuxt 3 + Prisma | Blog module, Auth, Payments | $149 | | [SuperSaaS](https://supersaas.dev){rel=""nofollow""} | Custom Backend Logic | Vue 3 + Node | Modular components, Stripe | $149 | | [Nuxt Starter Kit](https://nuxtstarterkit.com/){rel=""nofollow""} | Minimal | Nuxt + Tailwind | Authentication, Simple DB | $99 | --- ## In-Depth Review: The Best Options for 2026 ### 1. ShipAhead (Top Pick for Nuxt 4) **ShipAhead** is currently the **best Nuxt starter kit optimized for AI coding agents**. It is built explicitly for the Nuxt 4 era and focuses on a clean architecture that AI coding assistants like Cursor and Copilot can understand instantly. - **Pros:** Full Nuxt 4 support, Drizzle ORM (fastest), pre-built SEO modules, AI-native structure. - **Best For:** Developers who want to build high-quality apps with AI assistance. - **Nuxt JS Starter Kit** perfection: Uses the latest standards. ### 2. supastarter for Nuxt One of the most mature options on the market. If you need a **nuxt saas starter kit** that handles complex team management and multi-tenancy out of the box, this is it. - **Pros:** Extremely feature-rich, great documentation. - **Cons:** Higher price point, can be overkill for simple projects. ### 3. Nuxt Beyond Considered one of the top **Nuxt boilerplate alternatives**, **Nuxt Beyond** ([nuxtbeyond.com](https://nuxtbeyond.com/){rel=""nofollow""}) offers a robust, full-stack framework configured specifically for Nuxt ecosystem enthusiasts wanting extensive built-in capabilities. - **Pros:** Great baseline for full-stack applications. - **Best For:** Developers looking for a comprehensive, structured foundation. ### 4. Nuxt SaaS Kit A solid, middle-of-the-road option that has been around for a while. It's a reliable **nuxt js starter kit** for those using Prisma and standard relational databases. - **Pros:** Well-tested, great blog integration. --- ## How to Choose a Pre-configured solution for Web Development When you **compare popular Nuxt starter kits for beginners**, look beyond just the price. Ask these questions: 1. **Nuxt 4 Support:** Is the kit updated for the latest major version? 2. **Database Choice:** Do you prefer the simplicity of Supabase, or the control of Drizzle/Prisma? 3. **UI Library:** Does it use Nuxt UI, Tailwind, or something else you are comfortable with? 4. **Maintenance:** How often is the kit updated? --- ## FAQ: Nuxt Starter Kits & Rapid Development ### What is the best Nuxt starter kit for beginners? For beginners, the **official Nuxt UI starter** or **ShipAhead** are great because they have clean codebases and excellent documentation. ### Why choose a Nuxt 4 starter kit over Nuxt 3? **Nuxt 4 starter kits** offer better performance, a more refined folder structure (`app/` directory), and better typing support. It is always better to start with the latest version in 2026. ### Are there affordable Nuxt starter kits with built-in features? Yes, kits like **ShipAhead** and **NuxSaaS** offer lifetime licenses for under $150, which is a fraction of the cost of building these features manually. ### How do I choose between Nuxt UI and other UI kits? Choose a **nuxt ui starter kit** if you want the most integrated experience with the Nuxt ecosystem. It is built by the Nuxt team and follows all their best practices. --- ## Conclusion: Start Building Today The **best options for quickly starting a new web project** in 2026 all point towards using a high-quality boilerplate. Stop fighting with configurations and start shipping features. Ready to launch your next big idea? [Get ShipAhead](https://shipahe.ad){rel=""nofollow""} and join the founders who are building the future with Nuxt 4. # How to Upgrade Nuxt 3 to 4 in Under 10 Minutes – A Clear Guide Nuxt 4 is a massive shift in how we build and structure Vue apps. While major version updates can feel like a headache, staying on Nuxt 3 is just building up tech debt you’ll have to pay later. The jump to Nuxt 4 brings better performance, a cleaner `app/` directory, and a much tighter developer experience. Here is the no-nonsense migration guide to get your project upgraded in under 10 minutes. --- ## Why Should You Migrate to Nuxt 4 Now? Waiting to **modernize your Nuxt app** only makes it harder as your codebase grows. By upgrading now, you get: - **The "app/" Directory:** A much cleaner root folder that separates your business logic from your configuration. - **Improved Type Safety:** Better error catching while you write code. - **Faster Cold Starts:** Your development environment will feel snappier. --- ## Step 1: Update Your Dependencies The first step is to pull in the latest Nuxt package. Open your terminal and run: ```bash # Using npm npm install nuxt@latest # Using pnpm pnpm add nuxt@latest ``` This ensures you have the latest core binaries ready to handle the transformation. --- ## Step 2: Enable the Nuxt 4 Compatibility Version Nuxt 4 allows you to transition gradually. In your `nuxt.config.ts` file, you can set the compatibility version to `4`. This prepares your project for the new behaviors. ```typescript export default defineNuxtConfig({ future: { compatibilityVersion: 4, }, }); ``` --- ## Step 3: Shift to the New Directory Structure The biggest change in Nuxt 4 is the **Nuxt 4 directory structure**. Instead of having `pages/`, `components/`, and `composables/` in the root, they now live inside an `app/` folder. 1. Create an `app/` folder in your root directory. 2. Move your `pages/`, `layouts/`, `components/`, `composables/`, `middleware/`, and `plugins/` folders into it. 3. Rename `app.vue` to `app/app.vue` (if applicable). This separation keeps your root directory clean and focused on environment configuration. --- ## Step 4: Handle Nuxt 4 Breaking Changes While the migration tool handles most of the heavy lifting, you should manually check for common **Nuxt 4 breaking changes**: - **Scanning Changes:** Nuxt 4 is more strict about where it looks for files. If you have custom directories, you may need to register them in your config. - **Imports:** Ensure you aren't using deep imports from internal Nuxt packages that may have moved. - **Layer Compatibility:** If you use Nuxt Layers, ensure they also have the `compatibilityVersion: 4` flag. --- ## Step 5: Test and Verify Now, fire up your development server. ```bash npm run dev ``` Watch the terminal for any warnings or errors. If everything looks good, run your build command to ensure the production bundle is also generated without issues. --- ## Ready for a Fresh Start? If your Nuxt 3 project is too messy to upgrade, sometimes a fresh start is the best path forward. [ShipAhead](https://shipahe.ad){rel=""nofollow""} is built from the ground up on Nuxt 4. It includes all the best practices, the new directory structure, and modern auth integrated out of the box. Skip the migration headache and start building with the latest technology today. --- ## Final Thoughts The jump to Nuxt 4 is a major step forward for the Vue ecosystem. It simplifies your project and prepares you for the next few years of web development. Don't let your tech debt stay high—**Upgrade Nuxt 3 to 4** today and enjoy a faster development workflow. # Vibe Coding Your SaaS – The Modern Way to Build in 2026 Most of my best work happens when I'm not "grinding." It happens when I'm in a flow state, moving fast, and seeing my ideas come to life in real-time. Lately, the indie hacker community has been calling this **Vibe Coding**. It’s the opposite of the "Architecture Astronaut" approach where you spend weeks planning. Instead, you prioritize intuition and speed, using AI and pre-built stacks to handle the execution while you focus on the vision. Here’s how I use this workflow to ship faster than I ever could by hand. --- ## What Exactly is "Vibe Coding"? Vibe coding is a style of **intuitive software development** where you focus on the vision while AI and boilerplates handle the execution. You describe what you want, you experiment in real-time, and you let the app grow naturally. The core rules of vibe coding are: - **No Starting from Zero:** You never start with an empty folder. - **High-Context AI:** You use tools that understand your whole project. - **Rapid Feedback:** You see changes instantly and iterate based on "the vibe." --- ## Why Flow State is Your Competitive Advantage The biggest threat to your SaaS is boredom. If you spend three days trying to connect a database, you lose your momentum. **Building a SaaS in flow** means you never hit those "wall" moments that make you want to quit. To maintain these **modern development vibes**, you need a stack that doesn't get in your way. ### Step 1: Secure the Foundation You cannot "vibe" if you are writing login logic. Use [ShipAhead](https://shipahe.ad){rel=""nofollow""} to get the infrastructure out of the way. It provides a clean, pre-configured Nuxt 4 environment that is ready for your ideas. ### Step 2: Leverage AI Agents Tools like **Cursor** and **Claude** are the engines behind **vibe coding**. When you use a structured boilerplate, the AI knows exactly where things should go. You don't "write code"; you "guide the AI" through the project. --- ## How ShipAhead Enables Efficient SaaS Building We designed [ShipAhead](https://shipahe.ad){rel=""nofollow""} specifically for the vibe-coding era. It is not just a bunch of files; it is a system designed for maximum velocity. - **AI-Native Architecture:** Folders and files are named logically so AI coding agents can navigate your project without mistakes. - **Pre-styled Components:** Use our Tailwind library to build beautiful pages by simply describing them to the AI. - **Zero-Config Deployments:** One click and your "vibe" is live for the world to see. --- ## The Secret to Moving Fast Most founders move slowly because they are perfectionists about the wrong things. They spend weeks on a database schema that will change anyway. Vibe coding encourages you to ship the MVP (Minimum Viable Vibe) first. Get it live, see how it feels, and then refine. This is the heart of **efficient SaaS building**. --- ## Conclusion The future of software isn't just about "writing code." It is about having the best ideas and the best flow. If you want to experience the true power of **Vibe Coding SaaS**, stop wasting time on the setup. Grab [ShipAhead](https://shipahe.ad){rel=""nofollow""}, fire up your AI assistant, and build your business in the zone. Your best ideas are waiting. Start shipping.