Skip to content
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
b4634be
add support to JSON-based schema seed
atilafassina May 22, 2025
78f88e6
add support for `schemaPath` on vite-plugin
atilafassina May 22, 2025
3381615
add changeset
atilafassina May 22, 2025
17c69c2
update tanstack example
atilafassina May 22, 2025
2455f50
improve error message for bad schema
atilafassina May 23, 2025
0a7a873
add test for schema validation
atilafassina Jun 19, 2025
e7cbf22
move Zod to `package.dependencies` instead of `devDependencies`
atilafassina Jun 19, 2025
6fd46fe
move Zod to `package.dependencies` instead of `devDependencies`
atilafassina Jun 19, 2025
ddb4541
improve queries logic
atilafassina Jun 19, 2025
c84d061
update `pnpm-lock.yaml`
atilafassina Jun 19, 2025
24fa369
refactor: use SQL file instead of JSON
atilafassina Jun 25, 2025
f1ba604
adjust the configuration object on vite-plugin
atilafassina Jun 25, 2025
0f14684
update changelogs
atilafassina Jun 25, 2025
3beb140
update docs
atilafassina Jun 25, 2025
0727611
cleanup code
atilafassina Jun 26, 2025
7bd481d
rename `onCreate` to `seed`
atilafassina Jun 26, 2025
ee674f9
add referrer to examples
atilafassina Jun 26, 2025
77fc18a
update release tag
atilafassina Jun 26, 2025
4bd6fb0
set tanstack example to private
atilafassina Jun 26, 2025
4a6ebae
update lockfile
atilafassina Jun 26, 2025
06abf77
remove unused schema file
atilafassina Jun 26, 2025
6768f0b
add tests, fix test run for CI
atilafassina Jun 26, 2025
6aacd91
remove unused import
atilafassina Jun 26, 2025
12b009c
adjust JSDoc and fix typos (`referer`/`referrer`)
atilafassina Jun 26, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/quick-loops-jump.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@neondatabase/vite-plugin-postgres": minor
---

Add `seed` option to seed database with SQL script on initialization. This option accepts a path to a SQL file that will be executed after the database is created.
9 changes: 9 additions & 0 deletions .changeset/sweet-rabbits-shake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"neondb": minor
---

Add support for seeding a SQL script during database initialization. You can now provide a path to a SQL file that will be executed right after the database is created. Either via the prompt or with a command flag.

| Option | Description |
| ------------ | --------------------------------------------------- |
| `-s, --seed` | Path to SQL file to execute after database creation |
15 changes: 2 additions & 13 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,21 +77,10 @@ jobs:
CHANGELOG_ENTRY=$(awk "/## $VERSION/,/## [0-9]/" "$CHANGELOG_PATH" | sed '1d;$d')
git tag -a "$TAG" "$COMMIT" -m "Release $pkg@$VERSION"

# Add schema.json as asset for neondb package
if [ "$pkg" = "neondb" ] && [ -f "$PKG_DIR/dist/schema.json" ]; then
gh release create "$TAG" --notes "$CHANGELOG_ENTRY" --title "$pkg@$VERSION" "$PKG_DIR/dist/schema.json"
else
gh release create "$TAG" --notes "$CHANGELOG_ENTRY" --title "$pkg@$VERSION"
fi
gh release create "$TAG" --notes "$CHANGELOG_ENTRY" --title "$pkg@$VERSION"
else
git tag "$TAG" "$COMMIT"

# Add schema.json as asset for neondb package
if [ "$pkg" = "neondb" ] && [ -f "$PKG_DIR/dist/schema.json" ]; then
gh release create "$TAG" --notes "Release $pkg@$VERSION" --title "$pkg@$VERSION" "$PKG_DIR/dist/schema.json"
else
gh release create "$TAG" --notes "Release $pkg@$VERSION" --title "$pkg@$VERSION"
fi
gh release create "$TAG" --notes "Release $pkg@$VERSION" --title "$pkg@$VERSION"
fi
done
env:
Expand Down
16 changes: 15 additions & 1 deletion examples/react-spa/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,19 @@ import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";

export default defineConfig({
plugins: [postgresPlugin(), react()],
plugins: [
postgresPlugin({
/**
* @todo
* [IMPORTANT] This helps us understand where DB creations on Neon come from.
* Please change this as soon as you can, to add your project name:
*
* @example
* ""github:org/your-repo"
* "npm:your-package"
*/
referrer: "github:neondatabase/neondb/react-spa",
}),
react(),
],
});
17 changes: 16 additions & 1 deletion examples/tanstack-start/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,22 @@ import tsConfigPaths from "vite-tsconfig-paths";
export default defineConfig({
vite: {
plugins: [
postgresPlugin(),
postgresPlugin({
seed: {
type: "sql-script",
path: "./schema.sql",
},
/**
* @todo
* [IMPORTANT] This helps us understand where DB creations on Neon come from.
* Please change this as soon as you can, to add your project name:
*
* @example
* ""github:org/your-repo"
* "npm:your-package"
*/
referrer: "github:neondatabase/neondb/tanstack-start",
}),
tsConfigPaths({
projects: ["./tsconfig.json"],
}),
Expand Down
2 changes: 2 additions & 0 deletions examples/tanstack-start/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"description": "",
"main": "index.js",
"type": "module",
"private": true,
"scripts": {
"dev": "vinxi dev",
"build": "vinxi build",
Expand All @@ -25,6 +26,7 @@
"@types/react": "^19.0.10",
"@types/react-dom": "^19.0.4",
"@vitejs/plugin-react": "^4.3.4",
"neondb": "workspace:*",
"typescript": "^5.8.2",
"vite-tsconfig-paths": "^5.1.4"
}
Expand Down
11 changes: 11 additions & 0 deletions examples/tanstack-start/schema.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
name text
);

INSERT INTO users (name) VALUES
('John Lennon'),
('Paul McCartney'),
('George Harrison'),
('Ringo Starr'),
('George Martin');
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
"build": "pnpm --filter neondb build && pnpm --filter vite-plugin-postgres build",
"format": "biome check --error-on-warnings --fix",
"lint:ci": "biome ci --error-on-warnings",
"test:ci": "pnpm --recursive vitest --passWithNoTests",
"test:ci": "pnpm --recursive test:ci",
"prepare": "husky"
},
"lint-staged": {
"lint-staged": {
"*": "biome check --write --no-errors-on-unmatched --files-ignore-unknown=true"
},
"devDependencies": {
Expand Down
1 change: 1 addition & 0 deletions packages/neondb/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Options:
- `-y, --yes` Use defaults, skip prompts
- `-e, --env` Path to .env file (default: ./.env)
- `-k, --key` Env key for connection string (default: DATABASE_URL)
- `-s, --seed` Path to SQL file to execute after database creation
- `-h, --help` Show help

---
Expand Down
7 changes: 3 additions & 4 deletions packages/neondb/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,17 @@
"scripts": {
"build": "tsc --noEmit && tsup",
"test": "vitest --passWithNoTests",
"test:ci": "vitest run --passWithNoTests",
"tsc": "tsc",
"dry:run:prompt": "pnpm build && node dist/cli.js",
"dry:run": "pnpm build && node dist/cli.js --yes"
},
"devDependencies": {
"@release-it/conventional-changelog": "10.0.0",
"@types/node": "22.13.10",
"@vitest/coverage-v8": "3.0.9",
"console-fail-test": "0.5.0",
"husky": "9.1.7",
"lint-staged": "15.5.0",
"release-it": "18.1.2",
"tsup": "catalog:",
"typescript": "catalog:",
"vitest": "catalog:"
Expand All @@ -65,10 +64,10 @@
},
"dependencies": {
"@clack/prompts": "0.10.1",
"@neondatabase/serverless": "^1.0.0",
"dotenv": "^16.5.0",
"gradient-string": "^3.0.0",
"open": "^10.1.0",
"p-wait-for": "^5.0.2",
"zod": "^3.24.3"
"p-wait-for": "^5.0.2"
}
}
16 changes: 16 additions & 0 deletions packages/neondb/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ async function main() {
const {
env: flagEnvPath,
key: flagEnvKey,
sql: flagSeedPath,
yes: shouldUseDefaults,
} = getArgs();

Expand Down Expand Up @@ -93,6 +94,20 @@ async function main() {
if (!userInput.dotEnvKey) {
userInput.dotEnvKey = DEFAULTS.dotEnvKey;
log.step(messages.info.defaultEnvKey(userInput.dotEnvKey));
log.step(`using ${userInput.dotEnvKey} as the .env key`);
}
}

if (!flagSeedPath) {
userInput.seed = {
type: "sql-script",
path: await text({
message: messages.questions.seedPath,
}),
} as Defaults["seed"];

if (!userInput.seed?.path) {
userInput.seed = DEFAULTS.seed;
}
}

Expand All @@ -103,6 +118,7 @@ async function main() {
dotEnvFile: userInput.dotEnvPath,
dotEnvKey: userInput.dotEnvKey,
referrer: "npm:neondb/cli",
seed: userInput.seed,
});
}
s.stop("Database generated!");
Expand Down
15 changes: 14 additions & 1 deletion packages/neondb/src/lib/instant-neon.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { randomUUID } from "node:crypto";
import { readFile } from "node:fs/promises";
import { log } from "@clack/prompts";
import { seedDatabase } from "./seed-database.js";
import { messages } from "./texts.js";
import { InstantNeonParams } from "./types.js";
import type { InstantNeonParams } from "./types.js";
import { createClaimableDatabase } from "./utils/create-db.js";
import { getPoolerString } from "./utils/format.js";
import { writeToEnv } from "./utils/fs.js";
import { LAUNCHPAD_URLS } from "./utils/urls.js";

/**
* Creates an instant Postgres connection string from Instagres by Neon
* if not already set in the specified .env file.
Expand All @@ -16,6 +19,7 @@ export const instantNeon = async ({
dotEnvFile = ".env",
dotEnvKey = "DATABASE_URL",
referrer = "unknown",
seed = undefined,
}: InstantNeonParams) => {
const dbId = randomUUID();
const claimExpiresAt = new Date(Date.now() + 3 * 24 * 60 * 60 * 1000);
Expand All @@ -27,6 +31,7 @@ export const instantNeon = async ({
);
const claimUrl = new URL(LAUNCHPAD_URLS.CLAIM_DATABASE(dbId));
log.step(messages.botCheck(createDbUrl.href));

const connString = await createClaimableDatabase(dbId, createDbUrl);
const poolerString = getPoolerString(connString);

Expand All @@ -45,10 +50,18 @@ export const instantNeon = async ({
log.success(messages.envSuccess(dotEnvFile, dotEnvKey));
log.info(messages.databaseGenerated(claimUrl.href));

if (seed) {
log.step("Pushing schema to database");
await seedDatabase(seed.path, connString);
log.success("Schema pushed to database");
}

return {
databaseUrl: connString,
poolerUrl: poolerString,
claimUrl: claimUrl.href,
claimExpiresAt,
} as const;
};

export { InstantNeonParams };
66 changes: 0 additions & 66 deletions packages/neondb/src/lib/neon-schema.ts

This file was deleted.

14 changes: 14 additions & 0 deletions packages/neondb/src/lib/seed-database.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { neon } from "@neondatabase/serverless";
import { getSqlCommands } from "./utils/fs.js";

export async function seedDatabase(
schemaFilePath: string,
connectionString: string,
) {
const client = neon(connectionString);
const commands = getSqlCommands(schemaFilePath);

for (const command of commands) {
await client.query(command);
}
}
3 changes: 3 additions & 0 deletions packages/neondb/src/lib/texts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ ${url}
questions: {
dotEnvFilePath: `Enter the path to your environment file (default: ${DEFAULTS.dotEnvPath})`,
dotEnvKey: `Enter the key for the database connection string (default: ${DEFAULTS.dotEnvKey})`,
seedPath: `Enter the path to your seed (.sql) file (default: ${
DEFAULTS.seed?.path || "none"
})`,
},

info: {
Expand Down
11 changes: 8 additions & 3 deletions packages/neondb/src/lib/types.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
import { neonColumnTypeOptions } from "./neon-schema.js";
export type SqlScript = {
type: "sql-script";
path: string;
};

/**
* Parameters for configuring Instagres database connection
* @param {string} dotEnvFile - Path to the .env file where the connection string will be saved
* @param {string} dotEnvKey - Environment variable name to store the connection string
* @param {boolean} withPooler - Whether to use connection pooling
* @param {string} referer - referrer name for tracking
* @param {string} seedPath - Path to the `.sql` file to be pushed to the database
*/
export interface InstantNeonParams {
dotEnvFile?: string;
dotEnvKey?: string;
referrer?: string;
seed?: SqlScript;
}

export interface Defaults {
dotEnvPath: string;
dotEnvKey: string;
seed?: SqlScript;
}

export type NeonColumnTypes = (typeof neonColumnTypeOptions)[number]["value"];
Loading