Skip to content
GitHub Discord

AWS PlanetScale Drizzle MySQL

In this example, we use PlanetScale with a branch-per-stage pattern. Every stage gets its own database branch — so each PR can have an isolated database.

sst.config.ts
const db = planetscale.getDatabaseVitessOutput({
id: "mydb",
organization: "myorg",
});
const branch =
$app.stage === "production"
? planetscale.getVitessBranchOutput({
id: db.defaultBranch,
organization: db.organization,
database: db.name,
})
: new planetscale.VitessBranch("DatabaseBranch", {
database: db.name,
organization: db.organization,
name: $app.stage,
parentBranch: db.defaultBranch,
});

We then create a password and wrap it in a Linkable to link it to a function.

sst.config.ts
new sst.aws.Function("Api", {
handler: "src/api.handler",
link: [database],
url: true,
});

You can push your Drizzle schema changes to PlanetScale with:

Terminal window
bun run db:push

In the function we use Drizzle ORM with the Resource helper.

src/drizzle.ts
import { drizzle } from "drizzle-orm/planetscale-serverless";
import { Resource } from "sst";
export const db = drizzle({
connection: {
host: Resource.Database.host,
username: Resource.Database.username,
password: Resource.Database.password,
},
});
sst.config.ts
const db = planetscale.getDatabaseVitessOutput({
id: "example",
organization: "vimtor",
});
const branch =
$app.stage === "production"
? planetscale.getVitessBranchOutput({
id: db.defaultBranch,
organization: db.organization,
database: db.name,
})
: new planetscale.VitessBranch("DatabaseBranch", {
database: db.name,
organization: db.organization,
name: $app.stage,
parentBranch: db.defaultBranch,
});
const password = new planetscale.VitessBranchPassword("DatabasePassword", {
database: db.name,
organization: db.organization,
branch: branch.name,
role: "admin",
name: `${$app.name}-${$app.stage}`,
});
const database = new sst.Linkable("Database", {
properties: {
host: password.accessHostUrl,
username: password.username,
password: password.plainText,
database: db.name,
port: 3306,
},
});
const api = new sst.aws.Function("Api", {
handler: "src/api.handler",
link: [database],
url: true,
});
src/api.ts
import { db } from "./drizzle";
import { todosTable } from "./schema";
import { APIGatewayProxyHandlerV2 } from "aws-lambda";
export const handler: APIGatewayProxyHandlerV2 = async (evt) => {
if (evt.requestContext.http.method === "GET") {
const result = await db.select().from(todosTable).execute();
return {
statusCode: 200,
body: JSON.stringify(result),
};
}
if (evt.requestContext.http.method === "POST") {
await db.insert(todosTable).values({ title: "new todosTable" }).execute();
return {
statusCode: 200,
body: "created",
};
}
return {
statusCode: 404,
body: "not found",
};
};

View the full example.