create-supabase-saas 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +52 -0
  2. package/bin/index.js +169 -0
  3. package/package.json +37 -0
package/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # create-supabase-saas
2
+
3
+ > Scaffold a production-ready Next.js + Supabase SaaS app in seconds.
4
+
5
+ ```bash
6
+ npx create-supabase-saas my-app
7
+ # or
8
+ npm create supabase-saas my-app
9
+ # or
10
+ yarn create supabase-saas my-app
11
+ # or
12
+ pnpm create supabase-saas my-app
13
+ ```
14
+
15
+ ## What you get
16
+
17
+ - **Auth** — Email/password + Google OAuth + forgot/reset password (`@supabase/ssr`)
18
+ - **Multi-tenant orgs** — owner / admin / member / viewer roles with full RLS
19
+ - **Stripe** — Checkout, Billing Portal, 4 webhook events
20
+ - **Emails** — Welcome, invite, invoice (React Email + Resend)
21
+ - **Notifications bell** — In-app notifications with unread badge
22
+ - **API key management** — SHA-256 hashed, revocable
23
+ - **Audit log** — Append-only with SECURITY DEFINER
24
+ - **TypeScript strict** — `useUser`, `useSubscription`, `useOrg` hooks
25
+
26
+ **65 files. Zero configuration to start.**
27
+
28
+ ## Quick start
29
+
30
+ ```bash
31
+ npx create-supabase-saas my-saas
32
+
33
+ cd my-saas
34
+
35
+ # 1. Fill in your keys
36
+ cp .env.example .env.local # already done by the CLI
37
+ # edit .env.local → NEXT_PUBLIC_SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY, STRIPE_SECRET_KEY, RESEND_API_KEY
38
+
39
+ # 2. Push DB migrations
40
+ supabase db push
41
+
42
+ # 3. Run
43
+ npm run dev
44
+ ```
45
+
46
+ ## Template source
47
+
48
+ [github.com/Edraid/nextjs-supabase-saas-starter](https://github.com/Edraid/nextjs-supabase-saas-starter)
49
+
50
+ ## License
51
+
52
+ MIT
package/bin/index.js ADDED
@@ -0,0 +1,169 @@
1
+ #!/usr/bin/env node
2
+
3
+ import pc from 'picocolors';
4
+ import prompts from 'prompts';
5
+ import degit from 'degit';
6
+ import { execSync } from 'child_process';
7
+ import fs from 'fs';
8
+ import path from 'path';
9
+
10
+ const TEMPLATE_REPO = 'Edraid/nextjs-supabase-saas-starter';
11
+ const REPO_URL = 'https://github.com/Edraid/nextjs-supabase-saas-starter';
12
+
13
+ // ─── Banner ───────────────────────────────────────────────────────────────────
14
+
15
+ console.log(`
16
+ ${pc.bold(pc.cyan('create-supabase-saas'))} ${pc.dim('v1.0.0')}
17
+
18
+ ${pc.green('▸')} Next.js 15 App Router
19
+ ${pc.green('▸')} Supabase Auth + Multi-tenant orgs
20
+ ${pc.green('▸')} Stripe Checkout + Billing Portal
21
+ ${pc.green('▸')} React Email + Resend
22
+ ${pc.green('▸')} TypeScript strict + full RLS
23
+ `);
24
+
25
+ // ─── Get project name from args or prompt ─────────────────────────────────────
26
+
27
+ let projectName = process.argv[2];
28
+
29
+ if (!projectName) {
30
+ const response = await prompts(
31
+ {
32
+ type: 'text',
33
+ name: 'projectName',
34
+ message: 'What is your project named?',
35
+ initial: 'my-saas-app',
36
+ validate: (v) =>
37
+ /^[a-z0-9-_]+$/.test(v) || 'Only lowercase letters, numbers, hyphens and underscores',
38
+ },
39
+ { onCancel: () => process.exit(0) }
40
+ );
41
+ projectName = response.projectName;
42
+ }
43
+
44
+ if (!projectName) process.exit(0);
45
+
46
+ const targetDir = path.resolve(process.cwd(), projectName);
47
+
48
+ // ─── Check target dir ─────────────────────────────────────────────────────────
49
+
50
+ if (fs.existsSync(targetDir)) {
51
+ const { overwrite } = await prompts(
52
+ {
53
+ type: 'confirm',
54
+ name: 'overwrite',
55
+ message: `Directory ${pc.yellow(projectName)} already exists. Overwrite?`,
56
+ initial: false,
57
+ },
58
+ { onCancel: () => process.exit(0) }
59
+ );
60
+ if (!overwrite) {
61
+ console.log(pc.red('\nAborted.'));
62
+ process.exit(0);
63
+ }
64
+ fs.rmSync(targetDir, { recursive: true, force: true });
65
+ }
66
+
67
+ // ─── Package manager ──────────────────────────────────────────────────────────
68
+
69
+ const { pkgManager } = await prompts(
70
+ {
71
+ type: 'select',
72
+ name: 'pkgManager',
73
+ message: 'Which package manager do you use?',
74
+ choices: [
75
+ { title: 'npm', value: 'npm' },
76
+ { title: 'pnpm', value: 'pnpm' },
77
+ { title: 'yarn', value: 'yarn' },
78
+ { title: 'bun', value: 'bun' },
79
+ ],
80
+ initial: 0,
81
+ },
82
+ { onCancel: () => process.exit(0) }
83
+ );
84
+
85
+ // ─── Clone template ───────────────────────────────────────────────────────────
86
+
87
+ console.log(`\n${pc.cyan('◆')} Cloning template into ${pc.bold(projectName)}...`);
88
+
89
+ try {
90
+ const emitter = degit(TEMPLATE_REPO, {
91
+ cache: false,
92
+ force: true,
93
+ verbose: false,
94
+ });
95
+
96
+ await emitter.clone(targetDir);
97
+ } catch (err) {
98
+ console.error(pc.red(`\n✖ Failed to clone template: ${err.message}`));
99
+ console.error(pc.dim(` You can manually clone: git clone ${REPO_URL} ${projectName}`));
100
+ process.exit(1);
101
+ }
102
+
103
+ // ─── Update package.json with project name ────────────────────────────────────
104
+
105
+ const pkgPath = path.join(targetDir, 'package.json');
106
+ if (fs.existsSync(pkgPath)) {
107
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
108
+ pkg.name = projectName;
109
+ fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
110
+ }
111
+
112
+ // ─── Rename .env.example to .env.local ────────────────────────────────────────
113
+
114
+ const envExample = path.join(targetDir, '.env.example');
115
+ const envLocal = path.join(targetDir, '.env.local');
116
+ if (fs.existsSync(envExample) && !fs.existsSync(envLocal)) {
117
+ fs.copyFileSync(envExample, envLocal);
118
+ }
119
+
120
+ // ─── Install deps? ────────────────────────────────────────────────────────────
121
+
122
+ const { install } = await prompts(
123
+ {
124
+ type: 'confirm',
125
+ name: 'install',
126
+ message: `Install dependencies with ${pc.bold(pkgManager)}?`,
127
+ initial: true,
128
+ },
129
+ { onCancel: () => process.exit(0) }
130
+ );
131
+
132
+ if (install) {
133
+ console.log(`\n${pc.cyan('◆')} Installing dependencies...\n`);
134
+ try {
135
+ const installCmd = pkgManager === 'yarn' ? 'yarn' : `${pkgManager} install`;
136
+ execSync(installCmd, { cwd: targetDir, stdio: 'inherit' });
137
+ } catch {
138
+ console.log(pc.yellow('\n⚠ Install failed — run it manually inside the project folder.\n'));
139
+ }
140
+ }
141
+
142
+ // ─── Success ──────────────────────────────────────────────────────────────────
143
+
144
+ const cdCmd = projectName === '.' ? '' : ` cd ${projectName}\n`;
145
+ const runCmd = pkgManager === 'npm' ? 'npm run dev' :
146
+ pkgManager === 'yarn' ? 'yarn dev' :
147
+ `${pkgManager} dev`;
148
+
149
+ console.log(`
150
+ ${pc.green('✔')} ${pc.bold('Project created!')}
151
+
152
+ ${pc.bold('Next steps:')}
153
+
154
+ ${cdCmd} 1. Fill in ${pc.cyan('.env.local')} with your Supabase + Stripe + Resend keys
155
+ 2. Run Supabase migrations:
156
+ ${pc.dim('supabase db push')}
157
+ 3. Start the dev server:
158
+ ${pc.cyan(runCmd)}
159
+
160
+ ${pc.bold('Docs & config:')}
161
+ ${pc.dim('→')} ${pc.underline(REPO_URL)}
162
+ ${pc.dim('→')} CUSTOMIZATION.md (theming, auth providers, Stripe plans)
163
+ ${pc.dim('→')} CHANGELOG.md (what's new in v1.0.0)
164
+
165
+ ${pc.bold('Need the RLS-only pack?')}
166
+ ${pc.dim('→')} ${pc.underline('https://edraid-dev.lemonsqueezy.com')}
167
+
168
+ ${pc.dim('Happy building! ⚡')}
169
+ `);
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "create-supabase-saas",
3
+ "version": "1.0.0",
4
+ "description": "Create a Next.js + Supabase SaaS app with auth, multi-tenant orgs, Stripe, and emails in seconds",
5
+ "keywords": [
6
+ "nextjs",
7
+ "supabase",
8
+ "saas",
9
+ "starter",
10
+ "boilerplate",
11
+ "stripe",
12
+ "multi-tenant",
13
+ "create-app"
14
+ ],
15
+ "homepage": "https://github.com/Edraid/nextjs-supabase-saas-starter",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/Edraid/create-supabase-saas.git"
19
+ },
20
+ "license": "MIT",
21
+ "author": "Edraid",
22
+ "type": "module",
23
+ "bin": {
24
+ "create-supabase-saas": "bin/index.js"
25
+ },
26
+ "files": [
27
+ "bin"
28
+ ],
29
+ "dependencies": {
30
+ "degit": "^2.8.4",
31
+ "picocolors": "^1.1.1",
32
+ "prompts": "^2.4.2"
33
+ },
34
+ "engines": {
35
+ "node": ">=18.0.0"
36
+ }
37
+ }