Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
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
74 changes: 46 additions & 28 deletions docs/reference/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,33 @@ Use this page as a command reference. If you are setting up a project for the fi

## Cheat Sheet

| Command | Purpose |
| --------------------------------- | ------------------------------------------------ |
| `void deploy` | Build and deploy to Void |
| `void prepare` | Generate `.void` artifacts without starting Vite |
| `void gen model <name> [cols...]` | Scaffold migration + CRUD routes |
| `void gen route <path>` | Create an API route |
| `void db push` | Apply schema directly without migration files |
| `void db generate` | Generate SQL migrations from schema changes |
| `void db status` | Show local/remote migration status |
| `void db reset` | Drop and re-apply all migrations |
| `void db seed` | Reset + seed local database |
| `void db studio` | Open Drizzle Studio for local database |
| `void secret put <name=value>` | Set a production secret |
| `void secret list` | List production secrets |
| `void secret sync .env.local` | Bulk upload secrets from dotenv file |
| `void env check [--remote]` | Validate env.ts schema |
| `void env types` | Regenerate .void/env.d.ts from env.ts |
| `void env example` | Refresh the void-managed block in .env.example |
| `void auth login` | Authenticate with Void |
| `void project link` | Link directory to a project |
| `void project logs` | Show runtime logs from deployed project |
| `void project rollback` | Roll back to a previous deployment |
| `void project cancel` | Cancel an active deployment |
| `void project purge-cache` | Purge all cached pages |
| `void mcp` | Start the Void MCP server |
| `void init` | Setup wizard for new or existing projects |
| Command | Purpose |
| --------------------------------- | ------------------------------------------------------------------- |
| `void deploy` | Build and deploy to Void |
| `void prepare` | Generate `.void` artifacts without starting Vite |
| `void gen model <name> [cols...]` | Scaffold migration + CRUD routes |
| `void gen route <path>` | Create an API route |
| `void db push` | Apply schema directly without migration files |
| `void db generate` | Generate SQL migrations from schema changes |
| `void db status` | Show local/remote migration status |
| `void db reset` | Drop and re-apply all migrations |
| `void db seed` | Reset + seed local database |
| `void db execute <sql>` | Run SQL against the database (--remote for deployed) |
| `void db studio` | Open Drizzle Studio (--remote for the deployed PostgreSQL database) |
| `void secret put <name=value>` | Set a production secret |
| `void secret list` | List production secrets |
| `void secret sync .env.local` | Bulk upload secrets from dotenv file |
| `void env check [--remote]` | Validate env.ts schema |
| `void env types` | Regenerate .void/env.d.ts from env.ts |
| `void env example` | Refresh the void-managed block in .env.example |
| `void auth login` | Authenticate with Void |
| `void project link` | Link directory to a project |
| `void project logs` | Show runtime logs from deployed project |
| `void project rollback` | Roll back to a previous deployment |
| `void project cancel` | Cancel an active deployment |
| `void project purge-cache` | Purge all cached pages |
| `void mcp` | Start the Void MCP server |
| `void init` | Setup wizard for new or existing projects |

## Binary Invocation

Expand Down Expand Up @@ -289,9 +290,17 @@ Programmatic seed modules must export either a default function or a named `seed
```
void db execute <sql>
void db execute --file <path>
void db execute --remote <sql>
```

Run ad-hoc SQL against the local D1 database. Provide SQL inline or from a file. SELECT queries display results as a formatted table; other statements execute silently.
Run ad-hoc SQL against the database. Provide SQL inline or from a file. SELECT queries display results as a formatted table; other statements execute silently.

By default, targets the local database. Pass `--remote` to run against the deployed database:

- **D1 projects**: routes the query through the Void proxy (`proxy.void.cloud/d1/query`) using your auth token. No Cloudflare credentials needed.
- **PostgreSQL projects**: fetches the stored connection string from the platform and connects directly. Requires that `void db set-url` has been run at least once (the platform stores the URL encrypted). If the URL isn't stored yet, you will see: _"Run `void db set-url` once to populate it, then retry."_

For destructive statements (`DELETE`, `UPDATE`, `DROP`, etc.) when running in a TTY, you will be prompted to confirm before the query is sent to the deployed database. Non-TTY environments (CI) skip the prompt.

### `void db migrate`

Expand All @@ -305,7 +314,16 @@ Pass `--remote` to apply pending migrations to the remote database instead. Requ

### `void db studio`

Open [Drizzle Studio](https://orm.drizzle.team/docs/drizzle-kit-studio) for the local database. Launches a web-based GUI for browsing and editing your data.
```
void db studio [--remote]
```

Open [Drizzle Studio](https://orm.drizzle.team/docs/drizzle-kit-studio) for the database. Launches a web-based GUI for browsing and editing your data.

By default, targets the local database. Pass `--remote` to open Studio against the deployed database:

- **PostgreSQL projects**: fetches the stored connection string from the platform and opens Studio against it. Requires being logged in (`void auth login`) with a linked project. If the URL isn't stored yet, run `void db set-url` first.
- **D1 projects**: remote Studio is not yet supported. Use `void db execute --remote` for ad-hoc queries against your deployed D1 database.

### `void db rename-migrations`

Expand Down
14 changes: 14 additions & 0 deletions packages/void/src/cli/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -789,6 +789,20 @@ export class PlatformClient {
return res.json();
}

async getDatabaseUrl(projectId: string): Promise<{ url: string }> {
const res = await fetch(`${this.baseUrl}/projects/${projectId}/database-url`, {
headers: {
...this.authHeaders,
},
});

if (!res.ok) {
await throwPlatformApiError('Failed to fetch database URL', res);
}

return res.json();
}

async purgeCache(projectId: string): Promise<{ purged: number }> {
const res = await fetch(`${this.baseUrl}/projects/${projectId}/revalidate`, {
method: 'POST',
Expand Down
27 changes: 21 additions & 6 deletions packages/void/src/cli/db-args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,23 @@ export const dbSubcommands: Array<SubcommandDef> = [
description: 'Reset local DB, run migrations, and seed',
flags: [{ name: '--file', arg: '<path>', description: 'Seed from a specific file' }],
},
{ name: 'execute', arg: '<sql>', description: 'Run SQL against the local database' },
{
name: 'execute',
arg: '<sql>',
description: 'Run SQL against the database (use --remote for the deployed database)',
flags: [{ name: '--remote', description: 'Run against the deployed database' }],
},
{
name: 'migrate',
description: 'Apply pending migrations',
flags: [{ name: '--remote', description: 'Apply to the remote database' }],
},
{ name: 'studio', description: 'Open Drizzle Studio for the local database' },
{
name: 'studio',
description:
'Open Drizzle Studio against the database (use --remote for the deployed PostgreSQL database)',
flags: [{ name: '--remote', description: 'Open Studio against the deployed database' }],
},
{ name: 'set-url', description: 'Update the PostgreSQL connection string for deployment' },
{ name: 'rename-migrations', description: 'Rename migrations to timestamp-based format' },
{
Expand All @@ -38,9 +48,9 @@ export type DbArgs =
| { action: 'status' }
| { action: 'reset' }
| { action: 'seed'; file?: string }
| { action: 'execute'; command?: string; file?: string }
| { action: 'execute'; command?: string; file?: string; remote?: boolean }
| { action: 'migrate'; remote?: boolean }
| { action: 'studio' }
| { action: 'studio'; remote?: boolean }
| {
action: 'export';
output?: string;
Expand Down Expand Up @@ -116,7 +126,8 @@ export function parseDbArgs(args: Array<string>): DbArgs {
if (command && file) {
throw new Error('db: Provide either SQL inline or --file, not both.');
}
return { action, command, file };
const remote = parsed.values.remote === true ? true : undefined;
return { action, command, file, remote };
}

if (action === 'migrate') {
Expand All @@ -131,7 +142,8 @@ export function parseDbArgs(args: Array<string>): DbArgs {
if (rest.length > 0) {
throw new Error(`db: Unexpected argument '${rest[0]}'.`);
}
return { action };
const remote = parsed.values.remote === true ? true : undefined;
return { action, remote };
}

if (action === 'set-url') {
Expand All @@ -149,6 +161,9 @@ export function parseDbArgs(args: Array<string>): DbArgs {
}

if (action === 'export') {
if (parsed.values.remote === true) {
throw new Error('`void db export --remote` is not yet supported. Local export only for now.');
}
if (rest.length > 0) {
throw new Error(`db: Unexpected argument '${rest[0]}'.`);
}
Expand Down
Loading