---
title: "Studio Server Bridge"
description: "Drizzle Studio provides an interactive web-based interface for exploring and modifying database contents via the drizzle-kit studio command. The CLI Command Architecture parses parameters and valid..."
last_updated: "2026-10-12T08:14:00.734142+00:00"
canonical_url: "https://www.doc0.dev/docs/e1b68fed-3c4e-4c95-b2ba-ebf050f78025/technical/migration-toolkit/studio-server-bridge"
---

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [drizzle-kit/src/serializer/studio.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/studio.ts)
- [drizzle-kit/src/api.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/api.ts)
- [drizzle-kit/src/utils/certs.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/utils/certs.ts)
- [drizzle-kit/src/cli/schema.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/schema.ts)
- [drizzle-kit/src/cli/connections.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/connections.ts)
- [drizzle-kit/src/cli/commands/introspect.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/commands/introspect.ts)
- [drizzle-kit/src/cli/commands/sqliteIntrospect.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/commands/sqliteIntrospect.ts)
- [drizzle-orm/src/singlestore-proxy/driver.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/singlestore-proxy/driver.ts)
- [drizzle-orm/src/mysql-proxy/driver.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/mysql-proxy/driver.ts)
- [drizzle-orm/src/pg-proxy/driver.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/pg-proxy/driver.ts)
- [drizzle-kit/src/cli/index.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/index.ts)
- [drizzle-kit/src/cli/validations/studio.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/validations/studio.ts)
- [drizzle-kit/src/introspect-sqlite.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-sqlite.ts)
- [drizzle-kit/src/index.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/index.ts)
- [drizzle-orm/src/libsql/http/index.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/libsql/http/index.ts)
- [drizzle-kit/src/utils.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/utils.ts)
- [drizzle-kit/src/cli/commands/singlestoreUp.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/commands/singlestoreUp.ts)
- [drizzle-kit/src/cli/commands/singlestoreIntrospect.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/commands/singlestoreIntrospect.ts)
- [drizzle-kit/src/cli/validations/sqlite.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/validations/sqlite.ts)
- [integration-tests/drizzle2/pg-proxy/first/meta/_journal.json](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/integration-tests/drizzle2/pg-proxy/first/meta/_journal.json)
- [drizzle-kit/package.json](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/package.json)
- [drizzle-orm/src/singlestore-proxy/index.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/singlestore-proxy/index.ts)
- [drizzle-kit/src/serializer/mysqlImports.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/mysqlImports.ts)
- [drizzle-kit/src/serializer/pgImports.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/pgImports.ts)
- [drizzle-kit/src/serializer/singlestoreImports.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/singlestoreImports.ts)
</details>

## Overview

Drizzle Studio provides an interactive web-based interface for exploring and modifying database contents via the `drizzle-kit studio` command. The [CLI Command Architecture](https://www.doc0.dev/docs/e1b68fed-3c4e-4c95-b2ba-ebf050f78025/technical/migration-toolkit/cli-command-architecture) parses parameters and validates options from configuration files before initializing the server entrypoint. The [Configuration and Validations](https://www.doc0.dev/docs/e1b68fed-3c4e-4c95-b2ba-ebf050f78025/technical/migration-toolkit/configuration-and-validations) subsystem is responsible for resolving dialect choices, database credentials, and path globs from `drizzle.config.ts`.

Sources: [drizzle-kit/src/cli/schema.ts:652-675](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/schema.ts#L652-L675)

Automated self-signed TLS certificates are generated and cached in environment-specific paths using tools such as `mkcert` to secure HTTPS connections. If `mkcert` is missing or fails, the server falls back to plain HTTP.

Sources: [drizzle-kit/src/utils/certs.ts:15-44](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/utils/certs.ts#L15-L44)

Local HTTP and HTTPS servers are initialized to orchestrate session startup, while dialect-specific database connections leverage proxy drivers to bridge remote query execution. The proxy architecture provides a standardized callback interface documented in [Drivers And Runtimes](https://www.doc0.dev/docs/e1b68fed-3c4e-4c95-b2ba-ebf050f78025/technical/drivers-and-runtimes/drivers-and-runtimes) for executing raw queries across remote and serverless execution environments.

Sources: [drizzle-kit/src/serializer/studio.ts:832-847](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/studio.ts#L832-L847), [drizzle-orm/src/pg-proxy/driver.ts:27-61](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/pg-proxy/driver.ts#L27-L61)

Schema metadata serialization and relation extraction inspect exported TypeScript definitions to build normalized migration snapshots and relation graphs. For live databases, [Database Introspection](https://www.doc0.dev/docs/e1b68fed-3c4e-4c95-b2ba-ebf050f78025/technical/migration-toolkit/database-introspection) is used to inspect existing schemas and reverse-engineer structural snapshots before computing schema diffs.

Sources: [drizzle-kit/src/serializer/studio.ts:515-584](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/studio.ts#L515-L584)

## CLI Command Wiring and Configuration Validation

### Studio CLI Parameters and Schema Validation

The `studio` command defined in `drizzle-kit` uses Zod schemas to validate CLI options and configuration inputs. The command accepts custom options for network binding and configuration paths via `studioCliParams`, while `studioConfig` validates the database dialect, schema file paths or arrays, and casing options.

```typescript
export const studioCliParams = object({
	port: coerce.number().optional().default(4983),
	host: string().optional().default('127.0.0.1'),
	config: string().optional(),
});

export const studioConfig = object({
	dialect,
	schema: union([string(), string().array()]).optional(),
	casing: casingType.optional(),
});
```

Sources: [drizzle-kit/src/cli/validations/studio.ts:16-26](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/validations/studio.ts#L16-L26)

### Command Handler Execution Flow

When a user executes `drizzle-kit studio`, the handler checks core ORM versions, validates installed packages, and checks the Node.js runtime version. It then prepares the configuration, evaluates database credentials based on the selected dialect, and sets up dialect-specific database adapters.

```mermaid
flowchart TD
    A["studio handler"] --> B["assertOrmCoreVersion()"]
    B --> C["assertPackages('drizzle-orm')"]
    C --> D["assertStudioNodeVersion()"]
    D --> E["prepareStudioConfig(opts)"]
    E --> F{"Dialect check"}
    F -->|postgresql| G["preparePgSchema & drizzleForPostgres"]
    F -->|mysql| H["prepareMySqlSchema & drizzleForMySQL"]
    F -->|sqlite| I["prepareSQLiteSchema & drizzleForSQLite"]
    F -->|turso| J["prepareSQLiteSchema & drizzleForLibSQL"]
    F -->|singlestore| K["prepareSingleStoreSchema & drizzleForSingleStore"]
    F -->|gel| L["Exit: Studio not supported"]
    G --> M["prepareServer(setup)"]
    H --> M
    I --> M
    J --> M
    K --> M
    M --> N["server.start(...)"]
```

Sources: [drizzle-kit/src/cli/schema.ts:662-756](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/schema.ts#L662-L756)

### Supported CLI Options and Drivers

The Studio CLI command exposes specific parameters and driver version constraints that are validated at runtime before server startup.

| Option | Type | Default | Purpose |
| :--- | :--- | :--- | :--- |
| `port` | number | `4983` | Custom port for Drizzle Studio |
| `host` | string | `0.0.0.0` (CLI) / `127.0.0.1` (Validation) | Custom host for Drizzle Studio |
| `verbose` | boolean | `false` | Print all statements executed by Studio |
| `config` | string | `undefined` | Path to the configuration file |

Sources: [drizzle-kit/src/cli/schema.ts:654-661](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/schema.ts#L654-L661), [drizzle-kit/src/cli/validations/studio.ts:16-20](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/validations/studio.ts#L16-L20)

> [!CAUTION]
> Attempting to run the `studio` command with the `gel` dialect triggers an explicit termination via `process.exit(1)`, as Studio does not support Gel.
> 
> Sources: [drizzle-kit/src/cli/schema.ts:743-749](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/schema.ts#L743-L749)

> [!WARNING]
> Specific PostgreSQL drivers impose strict version checks on `drizzle-orm`. Using `aws-data-api` requires `drizzle-orm` version greater than `0.30.10`, and `pglite` requires version greater than `0.30.6`, otherwise the process exits with an error.
> 
> Sources: [drizzle-kit/src/cli/schema.ts:694-708](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/schema.ts#L694-L708)

## TLS Certificate Generation and Lifecycle

### Certificate Discovery and Storage Path

Drizzle-kit automates the provisioning of local self-signed TLS certificates for secure HTTPS Studio connections by leveraging `mkcert` and `env-paths`. When starting the server, `certs()` first inspects whether `mkcert` is installed by running `mkcert --help`.

Sources: [drizzle-kit/src/utils/certs.ts:15-18](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/utils/certs.ts#L15-L18)

If the command succeeds with an exit code of `0`, it resolves the platform-specific data directory using `env-paths` with the application name `drizzle-studio` and an empty suffix, ensuring the directory exists recursively.

Sources: [drizzle-kit/src/utils/certs.ts:19-25](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/utils/certs.ts#L19-L25)

### Caching and Generation Flow

Within the resolved data path, `drizzle-kit` looks for cached PEM files named `localhost-key.pem` and `localhost.pem`. It tests accessibility via `fs/promises` `access`, generating fresh credentials via `mkcert localhost` if missing.

Sources: [drizzle-kit/src/utils/certs.ts:26-36](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/utils/certs.ts#L26-L36)

Finally, it reads both files using UTF-8 encoding and returns them as a `{ key, cert }` object, falling back to `null` if `mkcert` is unavailable or if certificate generation fails.

Sources: [drizzle-kit/src/utils/certs.ts:37-44](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/utils/certs.ts#L37-L44)

> [!NOTE]
> If `mkcert` is not installed on the host machine, `certs()` returns `null`, causing the Studio server to fall back to plain HTTP connections instead of HTTPS.
> 
> Sources: [drizzle-kit/src/utils/certs.ts:15-43](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/utils/certs.ts#L15-L43), [drizzle-kit/src/api.ts:654](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/api.ts#L654)

## Local HTTP Server Initialization

### Server Setup and Listener Configuration

The initialization of the local Studio listener is orchestrated through `startServerFromSetup` in `api.ts` and `prepareServer` in `studio.ts`. Once the database setup and schema introspection wrappers are resolved, `startServerFromSetup` invokes `prepareServer(setup)` to construct the core request handler and server control handles. It defaults the binding host to `127.0.0.1` and the port to `4983` if explicit options are omitted, retrieves active TLS certificates via `certs()`, and invokes `server.start()` to spin up the underlying listener.

```typescript
const startServerFromSetup = async (setup: Setup, options?: {
	host?: string;
	port?: number;
}) => {
	const { prepareServer } = await import('./serializer/studio');

	const server = await prepareServer(setup);

	const host = options?.host || '127.0.0.1';
	const port = options?.port || 4983;
	const { key, cert } = (await certs()) || {};
	server.start({
		host,
		port,
		key,
		cert,
		cb: (err) => {
			if (err) {
				console.error(err);
			} else {
				console.log(`Studio is running at ${key ? 'https' : 'http'}://${host}:${port}`);
			}
		},
	});
};
```

Sources: [drizzle-kit/src/api.ts:634-658](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/api.ts#L634-L658)

### Listener Options and Execution Parameters

The `server.start()` method accepts a parameter object containing network binding properties and optional SSL credentials. When a TLS key is present, it explicitly configures Node's native `createServer` factory function alongside the provided private key and certificate paths.

| Parameter | Type | Default | Purpose |
| :--- | :--- | :--- | :--- |
| `host` | string | `127.0.0.1` (API) / `0.0.0.0` (CLI) | Hostname or IP address for the HTTP listener |
| `port` | number | `4983` | TCP port for the Studio server |
| `key` | string \| undefined | `undefined` | PEM-encoded private TLS key for HTTPS |
| `cert` | string \| undefined | `undefined` | PEM-encoded TLS certificate for HTTPS |
| `cb` | function | `(err) => void` | Callback executed after listener startup |

Sources: [drizzle-kit/src/serializer/studio.ts:831-847](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/studio.ts#L831-L847), [drizzle-kit/src/api.ts:642-657](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/api.ts#L642-L657)

```typescript
return {
	start: (params: Parameters<Server['start']>[0]) => {
		serve(
			{
				fetch: app!.fetch,
				createServer: params.key ? createServer : undefined,
				hostname: params.host,
				port: params.port,
				serverOptions: {
					key: params.key,
					cert: params.cert,
				},
			},
			() => params.cb(null, `${params.host}:${params.port}`),
		);
	},
};
```

Sources: [drizzle-kit/src/serializer/studio.ts:831-847](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/studio.ts#L831-L847)

> [!NOTE]
> The `serve` wrapper selectively binds `createServer` only when `params.key` is defined, enabling switching between secure HTTPS listeners and standard unencrypted HTTP streams depending on `mkcert` availability.
> 
> Sources: [drizzle-kit/src/serializer/studio.ts:833-843](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/studio.ts#L833-L843)

## Dialect Adapters and Remote Query Proxying

### Remote Database Sessions and Callbacks

The remote query proxy architecture bridges database interactions by instantiating dialect-specific remote sessions that delegate statement execution over asynchronous callback channels. In MySQL and SingleStore driver implementations, the `drizzle` factory function accepts a `RemoteCallback` alongside optional configuration properties like casing and loggers. This callback receives raw SQL strings, parameter bindings, and execution methods, returning a standardized result structure containing rows, insert identifiers, and affected row counts.

```typescript
export type RemoteCallback = (
	sql: string,
	params: any[],
	method: 'all' | 'execute',
) => Promise<{ rows: any[]; insertId?: number; affectedRows?: number }>;

export function drizzle<TSchema extends Record<string, unknown> = Record<string, never>>(
	callback: RemoteCallback,
	config: DrizzleConfig<TSchema> = {},
): MySqlRemoteDatabase<TSchema> {
```

Sources: [drizzle-orm/src/mysql-proxy/driver.ts:20-29](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/mysql-proxy/driver.ts#L20-L29)

```typescript
export type RemoteCallback = (
	sql: string,
	params: any[],
	method: 'all' | 'execute',
) => Promise<{ rows: any[]; insertId?: number; affectedRows?: number }>;
```

Sources: [drizzle-orm/src/singlestore-proxy/driver.ts:24-28](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/singlestore-proxy/driver.ts#L24-L28)

### Driver Session Classes and Dialect Binding

Both MySQL and SingleStore remote entrypoints instantiate specialized database and session classes to process query generation through their respective core dialects. The `MySqlRemoteDatabase` extends `MySqlDatabase` utilizing `MySqlRemoteQueryResultHKT`, `MySqlRemotePreparedQueryHKT`, and `MySqlRemoteSession`. Similarly, `SingleStoreRemoteDatabase` extends `SingleStoreDatabase` utilizing `SingleStoreRemoteQueryResultHKT`, `SingleStoreRemotePreparedQueryHKT`, and `SingleStoreRemoteSession`.

| Database Class | Dialect Class | Session Class | Query HKT Types |
| :--- | :--- | :--- | :--- |
| `MySqlRemoteDatabase` | `MySqlDialect` | `MySqlRemoteSession` | `MySqlRemoteQueryResultHKT`, `MySqlRemotePreparedQueryHKT` |
| `SingleStoreRemoteDatabase` | `SingleStoreDialect` | `SingleStoreRemoteSession` | `SingleStoreRemoteQueryResultHKT`, `SingleStoreRemotePreparedQueryHKT` |

Sources: [drizzle-orm/src/mysql-proxy/driver.ts:14-18](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/mysql-proxy/driver.ts#L14-L18), [drizzle-orm/src/mysql-proxy/driver.ts:30-55](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/mysql-proxy/driver.ts#L30-L55), [drizzle-orm/src/singlestore-proxy/driver.ts:18-22](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/singlestore-proxy/driver.ts#L18-L22), [drizzle-orm/src/singlestore-proxy/driver.ts:34-55](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/singlestore-proxy/driver.ts#L34-L55)

> [!NOTE]
> Schema tables passed into remote driver configurations are extracted via `extractTablesRelationalConfig` combined with `createTableRelationsHelpers`, binding table structures and map mappings directly to the database session instance.
> 
> Sources: [drizzle-orm/src/mysql-proxy/driver.ts:40-51](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/mysql-proxy/driver.ts#L40-L51), [drizzle-orm/src/singlestore-proxy/driver.ts:44-53](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/singlestore-proxy/driver.ts#L44-L53)

## Schema Serialization and Call-Chain Walkthrough

### Call-Chain Execution Walkthrough: PushSingleStoreSchema -> PrepareFromExports

The execution flow for `PushSingleStoreSchema -> PrepareFromExports` is traced through the following call order: `pushSingleStoreSchema` → `generateSingleStoreDrizzleJson` → `prepareFromExports`.

1. **Step 1 (`pushSingleStoreSchema`):** The operation begins in `drizzle-kit/src/api.ts` where `pushSingleStoreSchema` receives schema exports, a `SingleStoreDriverDatabase` instance, and a database name. It prepares the database query callback interface and invokes `generateSingleStoreDrizzleJson(imports)` to produce the target snapshot.
   Sources: [drizzle-kit/src/api.ts:545-565](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/api.ts#L545-L565)
2. **Step 2 (`generateSingleStoreDrizzleJson`):** In `drizzle-kit/src/api.ts`, `generateSingleStoreDrizzleJson` dynamically imports `prepareFromExports` from `./serializer/singlestoreImports` and calls `prepareFromExports(imports)` to isolate valid table exports. It generates a new random snapshot ID via `randomUUID()` and falls back to `originUUID` for `prevId` before invoking `generateSingleStoreSnapshot`.
   Sources: [drizzle-kit/src/api.ts:499-517](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/api.ts#L499-L517)
3. **Step 3 (`prepareFromExports`):** In `drizzle-kit/src/serializer/singlestoreImports.ts`, `prepareFromExports` iterates through `Object.values(exports)` and checks each export using `if (is(t, SingleStoreTable))` to filter and return `{ tables }`.
   Sources: [drizzle-kit/src/serializer/singlestoreImports.ts:6-22](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/singlestoreImports.ts#L6-L22)

```mermaid
sequenceDiagram
    participant api as drizzle-kit/src/api.ts
    participant singlestoreImports as drizzle-kit/src/serializer/singlestoreImports.ts
    participant singlestoreSerializer as drizzle-kit/src/serializer/singlestoreSerializer.ts
    api->>api: pushSingleStoreSchema(imports, drizzleInstance, databaseName)
    api->>api: generateSingleStoreDrizzleJson(imports)
    api->>singlestoreImports: prepareFromExports(imports)
    singlestoreImports-->>api: return { tables }
    api->>singlestoreSerializer: generateSingleStoreSnapshot(prepared.tables, casing)
    singlestoreSerializer-->>api: return snapshot
    api-->>api: return SingleStoreSchemaKit
```

Sources: [drizzle-kit/src/api.ts:499-565](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/api.ts#L499-L565), [drizzle-kit/src/serializer/singlestoreImports.ts:6-22](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/singlestoreImports.ts#L6-L22)

### Relational Schema Configuration and Relation Extraction

Studio requires a complete model of relations across tables. The `extractRelations` function processes relational table definitions extracted by Drizzle ORM, resolving foreign keys, casing adjustments, and referenced schemas across dialects:

```typescript
export const extractRelations = (
	tablesConfig: {
		tables: TablesRelationalConfig;
		tableNamesMap: Record<string, string>;
	},
	casing?: CasingType,
): Relation[] => {
	const relations = Object.values(tablesConfig.tables)
		.map((it) =>
			Object.entries(it.relations).map(([name, relation]) => {
				try {
					const normalized = normalizeRelation(
						tablesConfig.tables,
						tablesConfig.tableNamesMap,
						relation,
					);
					const rel = relation;
					const refTableName = rel.referencedTableName;
					const refTable = rel.referencedTable;
					const fields = normalized.fields
						.map((it) => getColumnCasing(it, casing))
						.flat();
					const refColumns = normalized.references
						.map((it) => getColumnCasing(it, casing))
						.flat();

					let refSchema: string | undefined;
					if (is(refTable, PgTable)) {
						refSchema = pgTableConfig(refTable).schema;
					} else if (is(refTable, MySqlTable)) {
						refSchema = mysqlTableConfig(refTable).schema;
					} else if (is(refTable, SQLiteTable)) {
						refSchema = undefined;
					} else if (is(refTable, SingleStoreTable)) {
						refSchema = singlestoreTableConfig(refTable).schema;
					} else {
						throw new Error('unsupported dialect');
					}

					let type: 'one' | 'many';
					if (is(rel, One)) {
						type = 'one';
					} else if (is(rel, Many)) {
						type = 'many';
					} else {
						throw new Error('unsupported relation type');
					}

					return {
						name,
						type,
						table: it.dbName,
						schema: it.schema || 'public',
						columns: fields,
						refTable: refTableName,
						refSchema: refSchema || 'public',
						refColumns: refColumns,
					};
				} catch {
					throw new Error(
						`Invalid relation "${relation.fieldName}" for table "${
							it.schema ? `${it.schema}.${it.dbName}` : it.dbName
						}"`,
					);
				}
			})
		)
		.flat();
	return relations;
};
```

Sources: [drizzle-kit/src/serializer/studio.ts:515-584](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/studio.ts#L515-L584)

> [!WARNING]
> Relation extraction will catch errors and issue console warnings if table relations are ambiguous or misconfigured, guiding developers to verify schema definitions against disambiguation documentation.
> 
> Sources: [drizzle-kit/src/serializer/studio.ts:758-771](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/studio.ts#L758-L771)

## Serialization Details and Design Trade-offs

### Serialization Transformers and Data Formatting

When Studio requests initialization metadata or executes proxy queries, responses undergo specific transformations in `jsonStringify` before being serialized. This custom serializer addresses JavaScript data types that do not natively map to standard JSON primitives:

| Data Type | Detection Condition | Serialized Representation | Rationale |
| :--- | :--- | :--- | :--- |
| `Error` | `value instanceof Error` | `{ error: value.message }` | Prevents empty object serialization of error instances |
| `bigint` | `typeof value === 'bigint'` | `value.toString()` | Avoids `TypeError: Do not know how to serialize a BigInt` |
| `Buffer` | `value instanceof Buffer` \|\| `value.type === 'Buffer'` | Base64 string via `Buffer.from(value).toString('base64')` | Ensures binary database blobs transmit over HTTP JSON APIs safely |
| `ArrayBuffer` | `value instanceof ArrayBuffer` | Base64 string via `Buffer.from(value).toString('base64')` | Allows browser/typed array binary buffers to serialize |

Sources: [drizzle-kit/src/serializer/studio.ts:645-670](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/studio.ts#L645-L670)

### Design Trade-offs

The architectural design of the Studio Server Bridge balances local developer experience with lightweight server execution:

| Design Choice | Benefit | Cost |
| :--- | :--- | :--- |
| CLI-driven child process execution (`mkcert`) | Avoids native OpenSSL dependencies and manages local CA trusts automatically | Requires external `mkcert` binary on the host machine path or falls back to HTTP [drizzle-kit/src/utils/certs.ts:16-43](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/utils/certs.ts#L16-L43) |
| In-memory proxy callback dispatching | Reuses dialect-specific ORM drivers without maintaining permanent database pools | Lacks persistent cross-query transaction handles for certain serverless drivers [drizzle-kit/src/cli/connections.ts:112-114](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/connections.ts#L112-L114) |
| Base64 binary serialization in JSON replacer | Transmits binary data and byte buffers without special transport layers | Increases payload transfer size for large binary columns [drizzle-kit/src/serializer/studio.ts:669](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/studio.ts#L669) |
| Dynamic runtime imports of dialects and drivers | Reduces CLI startup time by deferring heavy database drivers | Introduces async require/import latency on first command dispatch [drizzle-kit/src/cli/schema.ts:677-688](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/schema.ts#L677-L688) |

Sources: [drizzle-kit/src/utils/certs.ts:16-43](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/utils/certs.ts#L16-L43), [drizzle-kit/src/cli/connections.ts:112-114](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/connections.ts#L112-L114), [drizzle-kit/src/serializer/studio.ts:669](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/studio.ts#L669), [drizzle-kit/src/cli/schema.ts:677-688](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/schema.ts#L677-L688)

### Runnable API Usage Example

The Studio server can also be launched programmatically via the `startStudioPostgresServer` or `startStudioMySQLServer` APIs exposed in `drizzle-kit/api`:

```typescript
import { startStudioPostgresServer } from 'drizzle-kit/api';
import { pgTable, serial, text } from 'drizzle-orm/pg-core';

const users = pgTable('users', {
	id: serial('id').primaryKey(),
	name: text('name').notNull(),
});

await startStudioPostgresServer(
	{ users },
	{
		host: '127.0.0.1',
		port: 5432,
		user: 'postgres',
		password: 'password',
		database: 'app_db',
	},
	{
		host: '127.0.0.1',
		port: 4983,
	},
);
```

Sources: [drizzle-kit/src/api.ts:205-221](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/api.ts#L205-L221), [drizzle-kit/src/api.ts:634-658](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/api.ts#L634-L658)

## Related

- [CLI Command Architecture](https://www.doc0.dev/docs/e1b68fed-3c4e-4c95-b2ba-ebf050f78025/technical/migration-toolkit/cli-command-architecture)
- [Migration Toolkit Schema](https://www.doc0.dev/docs/e1b68fed-3c4e-4c95-b2ba-ebf050f78025/technical/migration-toolkit/migration-toolkit-schema)


## Sitemap

See the full [sitemap](https://www.doc0.dev/docs/e1b68fed-3c4e-4c95-b2ba-ebf050f78025/llms.txt) for all pages in this wiki.
