# Create a build template Contribute a starter app to the Stripe Projects template registry so developers can use it to build a new app with one command. For more details, see the [Stripe CLI reference](https://docs.stripe.com/cli.md). A build template is a working starter app that you can create a project from with `stripe projects build`. The app is a standalone GitHub repo containing app code, config files, and deployment setup. A short manifest in the template registry points to that repository and declares which Stripe Projects services the app uses. By contributing a template to the registry, you make it discoverable by framework, provider, or use case. ## How it works Use one command to build a starter app. You need the following: - **The Stripe CLI**: Runs `stripe projects build`. It reads the registry, copies the template files, installs dependencies, and provisions services. You don’t change the CLI to publish a template. - **The template registry**: A shared, public repo where each template gets a short YAML manifest. The manifest tells the CLI the location of your repo, which framework it uses, and what services it needs. You add your template by opening a pull request against this repo. - **Your template repo**: A public GitHub repo with a working starter app. You own it, maintain it, and control updates. The registry never holds your code, only a pointer to it and a pinned commit. When a developer selects your template, the CLI: 1. Reads the manifest from the registry. 2. Copies the template files from your repo at the pinned commit into a new project directory. 3. Runs the install command. 4. Sets up the Stripe project workspace. 5. Provisions the declared services. 6. Prints the next steps you defined. ### Developer discovery Every template in the registry is searchable by name, description, tags, and owner. Developers can browse or search and select your template directly. `stripe projects build` also offers a guided flow that narrows down templates step by step. It asks what type of app the developer is building (the category), then which framework they want, then their expected traffic. It filters the registry to matching templates and presents a recommendation. ``` What type of application are you building? Use ↑/↓ to move, Enter to select, Esc to cancel ╭──────────────────────────────────────────────────────────────────────╮ │ SaaS App │ │ ──────────────────────────────────────────────────────────────────── │ │ Subscription-based application with recurring billing. │ │ │ │ 4 templates available │ ╰──────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────╮ │ One-time payment app │ │ ──────────────────────────────────────────────────────────────────── │ │ Sell products or services with a single checkout. │ │ │ │ 5 templates available │ ╰──────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────╮ │ Static site │ │ ──────────────────────────────────────────────────────────────────── │ │ Marketing page, docs, or content site with Stripe checkout. │ │ │ │ 1 template available │ ╰──────────────────────────────────────────────────────────────────────╯ ``` After the developer answers the prompts, the CLI shows a recommended template: ``` Recommended Stack ╭──────────────────────────────────────────────────────────────────────╮ │ Next.js SaaS Starter │ │ ──────────────────────────────────────────────────────────────────── │ │ Description Subscription SaaS with auth, database, and billing │ │ Owner stripe │ │ │ │ Tier Free / lowest cost │ │ │ │ Vercel (hosting) $0/mo │ │ • An application deployed from a Git repository... │ │ │ │ Clerk (auth) $0/mo │ │ • Clerk Authentication - drop-in auth for any... │ │ │ │ Neon Postgres (database) $0/mo │ │ • Postgres with built-in auth - by Databricks │ │ │ │ Variants Vercel • Neon • Clerk │ │ Netlify • Render Postgres • Clerk │ │ Vercel • Render Postgres • Clerk │ │ Netlify • Neon • Clerk │ ╰──────────────────────────────────────────────────────────────────────╯ ``` ## Build a template ## Create your template repo Set up a public GitHub repo containing everything you need to clone, install, and run the project: app code, package files, deployment config, and a README. One repo can hold a single template at its root, or several templates in separate subdirectories. The registry points at a specific commit, so updates don’t affect existing users until you bump the pinned ref. Your template code must use the services listed in your manifest. When the CLI provisions a service (for example, `neon/postgres`), it produces environment variables (for example, `DATABASE_URL`). Your template reads from those environment variables so that everything works immediately after setup, with no manual configuration. Build your app to use the environment variables that each service in your `services` list provides, and the CLI handles the rest. ## Write the manifest The [template registry](https://github.com/stripe/projects-template-registry) is a public, open-source repo. It holds only manifests, not app code, so each manifest points to a public GitHub repo and a pinned commit. The repo is organized like this: ``` projects-template-registry/ ├── guided.yaml # Guided-flow categories, in display order ├── example/example.yaml # Commented reference manifest to copy ├── nextjs_saas/ # One directory per template family │ ├── amber-fox.yaml # One file per variant, named after the variant │ ├── harbor-mist.yaml │ └── ... ├── nextjs_one_time_payment/ │ └── ... └── simple_landing_page/ └── clear-sky.yaml ``` Each manifest describes one variant of a template. Group related variants in a directory named after the template family, and name each file after its variant. The file can use a `.yaml` or `.yml` extension. The filename is yours to choose, because the CLI reads the `template` and `variant` fields inside the file, not the path. The following is a complete example manifest with comments explaining each field. You can also copy [`example/example.yaml`](https://github.com/stripe/projects-template-registry/blob/main/example/example.yaml) from the registry as a starting point. ```yaml # Choose which guided category this template appears under. guided: category: saas # Pick the framework filter key this template should match in guided mode. framework: nextjs # Use one shared template id for all variants of the same starter. template: stripe/nextjs-saas # Give this concrete variant its own stable id. variant: amber-fox # Set this to true for the variant the CLI needs to recommend first. default: true # Write the short summary shown in the variant picker. variant_description: Vercel • Neon • Clerk # Optionally run one shell command after files are copied into the new project. install_command: npm install metadata: # Show this human-friendly name in browse results and confirmation cards. name: Next.js SaaS Starter # Explain in one line what the starter gives the user. description: Subscription SaaS with auth, database, and billing # Name the team or person maintaining this template. owner: stripe # Add optional search keywords to improve browse and search results. tags: - Billing - SaaS - Next.js # Point to the repo directory the CLI should copy from. repo: https://github.com/stripe/projects-templates/tree/main/nextjs_saas_amber-fox # Pin the exact commit so users get a reproducible template. ref: 84315765f28e9ad2d0b3c7167447edf6f65bcebe # List the provider services the CLI should provision. services: - vercel/project - clerk/auth - neon/postgres # Optionally list the commands the CLI should print after setup finishes. next_steps: # Use a short heading so users know what this command is for. - label: Run locally # Print the exact command the user should run next. command: npm run dev # Add as many labeled next-step commands as you want. - label: Build product with Codex command: codex "Help me turn this into a real product. Follow prompts/starter-to-product.md." - label: Build product with Claude command: claude "Help me turn this into a real product. Follow prompts/starter-to-product.md." - label: Deploy command: npm run deploy ``` ## Test app locally You don’t need to open a registry pull request to try your template. While you’re developing, point the CLI straight at a local manifest file: ```bash stripe projects build my-app --template-manifest /absolute/path/to/manifest.yaml ``` This is the fastest loop, and it works before your repo is public. While the template is still in development, you can leave `ref` empty in the local manifest. To preview how your template appears in the full guided flow, point the CLI at a local checkout of the registry instead. Clone the registry, add your manifest to the checkout, then set `STRIPE_PROJECTS_REGISTRY_PATH` to the registry directory: ```bash git clone https://github.com/stripe/projects-template-registry.git STRIPE_PROJECTS_REGISTRY_PATH=/absolute/path/to/projects-template-registry stripe projects build ``` To skip the guided picker and select a template directly, pass `--template`. It accepts either the full variant ID (`template/variant`) or just the template (`template`): ```bash stripe projects build my-app --template stripe/nextjs-saas/amber-fox ``` ## Submit to the registry When your template works locally and your repo is public, publish it so other developers can find it: 1. Push your template repo to a public GitHub repo and choose the exact commit you want users to receive. 2. Fork the [template registry](https://github.com/stripe/projects-template-registry) and add your manifest as `/.yaml`. 3. Set `repo` to your public repo (use a `/tree//` URL if the template is in a subdirectory) and set `ref` to the pinned commit. 4. Open a pull request against the registry. The registry entry is only an index record. Your code stays in your own repo, and you control updates by bumping the pinned `ref`. ## Manifest field reference Each manifest is a YAML file that describes one variant of a template. The following sections cover every field the registry parser accepts. ### Guided flow categories and frameworks Every manifest must include `guided.category` and `guided.framework`, which determine where your template appears in the guided flow. The available categories are `saas` (SaaS App), `one_time_payment` (One-time payment app), and `static_site` (Static site). If `guided.category` doesn’t match one of these keys, your template appears under “Something else” in the guided flow. Frameworks use lowercase identifiers such as `nextjs` and `tanstack-start`. If you pick “SaaS App” and then “Next.js”, your template appears in the results if it has `category: saas` and `framework: nextjs`. If your template has multiple variants (for example, one using Vercel and Neon and Clerk, and another using Cloudflare and Turso and Auth0), the guided flow groups them by `template` and shows a variant picker so the developer can choose between them. ### Required fields Every manifest must include these fields. The registry parser rejects entries that are missing any of them. | Field | Description | | --- | --- | | `guided.category` | The app type category. Must match `^[a-z0-9][a-z0-9_-]*$`. Determines which group your template is part of during the guided flow. Also used for browse and search tag derivation. | | `guided.framework` | The framework identifier. Same format as `category`. Determines which framework filter applies to your template in the guided flow. | | `template` | The logical grouping key for variants. All variants of the same starter share this value, for example `stripe/nextjs-saas`. | | `variant` | The concrete variant ID within a template group. The runtime ID becomes `${template}/${variant}` (for example, `stripe/nextjs-saas/amber-fox`). | | `default` | Controls variant ordering within a template group. `true` sorts before `false`, then ties sort alphabetically by variant name. | | `variant_description` | Text shown in the guided variant picker, typically a list of key providers (for example, `Vercel • Neon • Clerk`). Write it exactly as you want it displayed. | | `metadata.name` | Primary display name shown in browse cards and confirmations. | | `metadata.description` | One-line explanation of what the starter gives the user. | | `metadata.owner` | Who maintains the template. Shown in browse cards. | | `repo` | Source repo or tree URL the template materializes from. Typically a GitHub tree URL pointing at a repo subdirectory. | | `ref` | Pinned commit SHA for reproducible materialization. Users always get this exact snapshot. Update this when you want users to get a newer version. | | `services` | List of provisioned Projects service identifiers in `provider/service` format (for example, `vercel/project`, `clerk/auth`, `neon/postgres`). The CLI provisions these automatically when a user selects the template. | ### Optional fields Add these fields when they improve the user experience for your template. | Field | Description | | --- | --- | | `metadata.tags` | Free-form browse and search tags. Search uses these plus derived tags from `guided.category` and `guided.framework`. Add tags for technologies or providers not captured by required fields. | | `install_command` | Shell command the CLI runs after files are copied into the new project. Defaults to `npm install` if you omit it. Can be a compound command (for example, `pnpm install && pnpm generate`). Use this to install dependencies, run code generation, or perform any other one-time setup the template needs before you can start working. | | `service_overrides` | Override presentation metadata for a specific service without changing provisioning. Keyed by service identifier. Supported subfields: `label` (overrides display name) and `category` (overrides presentation category). | | `next_steps` | List of commands the CLI prints after setup finishes, giving the developer a clear path forward. Each item has a `label` (a short heading describing what the command does) and a `command` (the exact command to print). You can include as many items as you want: running locally, building with a coding agent, deploying, or anything else relevant to your template. | | `tier_plans` | Maps guided traffic tiers to a specific provider plan per service, so the CLI can provision without prompting. See [Tier plans](https://docs.stripe.com/projects/templates.md#tier-plans). | ### Tier plans Use `tier_plans` to map guided traffic tiers to specific plans for each service. Keyed by provisioned service identifier, each tier accepts either a plan identifier string or a configuration object: ```yaml # String form tier_plans: vercel/project: free_lowest_cost: Vercel/hobby starter_paid: Vercel/pro higher_scale: Vercel/pro # Config form tier_plans: cloudflare/workers: free_lowest_cost: plan: workers:free starter_paid: plan: workers:paid higher_scale: plan: workers:paid ``` Supported tier keys: `free_lowest_cost`, `starter_paid`, `higher_scale`. ## Requirements Every template must meet these requirements: 1. **Run locally with one command.** After setup, the project runs without errors. Ideally, all environment variables are provided by Projects services. If you need additional variables, document them in an `.env.example` file. 2. **Include at least one Stripe Projects service.** The template must use at least one provider available through [Stripe Projects](https://docs.stripe.com/projects.md). This connects the template to the Projects ecosystem and enables automatic provisioning. 3. **Match the manifest.** If your manifest lists `clerk/auth` and `neon/postgres`, your repo must use Clerk and Neon. ## Troubleshooting - **Your template doesn’t appear in the guided flow.** Check that `guided.category` matches a key in `guided.yaml`, otherwise it appears under “Something else.” When testing with a local registry, confirm you added the manifest to the right directory in your checkout. - **`STRIPE_PROJECTS_REGISTRY_PATH` has no effect.** It must point at the registry directory, not at a single YAML file. - **The CLI can’t find your files.** If your template lives in a subdirectory, set `repo` to a `/tree//` URL that includes the subdirectory. - **Published builds aren’t reproducible.** Set `ref` to a pinned commit SHA. An empty `ref` is only for local development with `--template-manifest`. - **A service still asks for input.** Some providers need a plan before they can provision without prompting. Add `tier_plans` so the CLI can pick a plan for each traffic tier. - **A provider fails after files are copied.** The CLI still creates your project, so the developer can add or fix services afterward. ## See also - [Stripe Projects CLI](https://docs.stripe.com/projects.md) - [Provider intake for Stripe Projects](https://docs.stripe.com/projects/provider-intake.md) - [Projects for platforms](https://docs.stripe.com/projects/platform-integration.md)