SvelteKit-D1-Drizzle-Example Svelte Themes

Sveltekit D1 Drizzle Example

SvelteKit Example CRUD using D1 Cloudflare and Drizzle ORM

Building a "Flat Comic" CRUD App with SvelteKit, Drizzle ORM, and Cloudflare D1

In this tutorial, we'll walk through building a high-performance, edge-ready CRUD application. We'll use SvelteKit for the framework, Drizzle ORM for type-safe database access, and Cloudflare D1 for our SQLite database at the edge. Plus, we'll give it a unique Neubrutalist "Flat Comic" UI style using Tailwind CSS.

Prerequisites

  • Basic knowledge of Svelte/SvelteKit.
  • Node.js and pnpm (or npm/yarn).
  • A Cloudflare account.

Step 1: Project Initialization

First, let's create a new SvelteKit project and install the necessary dependencies for Drizzle and Cloudflare.

pnpm dlx sv create my-blog
cd my-blog
pnpm add drizzle-orm @libsql/client
pnpm add -D drizzle-kit wrangler @sveltejs/adapter-cloudflare

Step 2: Define your Schema with Drizzle

In Drizzle, we define our database structure using TypeScript. Create a file at src/lib/server/db/schema.ts:

// src/lib/server/db/schema.ts
import { sqliteTable, text } from 'drizzle-orm/sqlite-core';

export const todo = sqliteTable('todo', {
    id: text('id')
        .primaryKey()
        .$defaultFn(() => crypto.randomUUID()),
    text: text('todo')
});

Drizzle turns this TypeScript definition into SQL migrations and provides full type safety for your queries.

Step 3: Configure Cloudflare D1

Cloudflare D1 is a serverless SQLite database. We configure it in wrangler.jsonc:

{
  "name": "my-blog",
  "compatibility_date": "2024-01-01",
  "d1_databases": [
    {
      "binding": "DB",
      "database_name": "my-db",
      "database_id": "your-id-here"
    }
  ]
}

3.1 Master the Wrangler CLI

The wrangler CLI is your gateway to Cloudflare's edge. Here is the step-by-step workflow to get your database live:

  1. Authentication: Link your terminal to your Cloudflare account.

    pnpm wrangler login
    
  2. Creation: Create the physical D1 database on Cloudflare's network.

    pnpm wrangler d1 create blog
    

    Note: Copy the database_id from the terminal output and paste it into your wrangler.jsonc!

  3. Local Execution: Run your migrations against your local development database.

    pnpm wrangler d1 migrations apply blog --local
    
  4. Production Sync: When you're ready to go live, apply those same migrations to the remote database.

    pnpm wrangler d1 migrations apply blog --remote
    
  5. Inspection: Want to see your data from the CLI?

    pnpm wrangler d1 execute blog --remote --command "SELECT * FROM todo;"
    

⚡ Wrangler & Drizzle Cheatsheet

Use these commands to manage your database lifecycle efficiently:

Action Command
Generate Migration pnpm drizzle-kit generate (Creates SQL files from schema)
Push Schema (Sync) pnpm drizzle-kit push (Fast sync without migrations)
Apply Local Migrations pnpm wrangler d1 migrations apply blog --local
Apply Remote Migrations pnpm wrangler d1 migrations apply blog --remote
Reset Local Database rm -rf .wrangler/state/v3/d1 (Wipes local D1 data/cache)
Drop Remote Table pnpm wrangler d1 execute blog --remote --command "DROP TABLE todo;"
List All Databases pnpm wrangler d1 list
Open DB Studio pnpm drizzle-kit studio (Visual explorer for your data)

Step 4: Connecting Drizzle to SvelteKit

To make our database accessible everywhere in our app, we'll use SvelteKit's hooks.server.ts. This runs on every request.

// src/hooks.server.ts
import { drizzle } from 'drizzle-orm/d1';
import { handle } from '@sveltejs/kit';

export const handle = async ({ event, resolve }) => {
    // Inject the Drizzle client into event.locals
    event.locals.db = drizzle(event.platform?.env.DB);
    return resolve(event);
};

Don't forget to update src/app.d.ts to include the db type in Locals!

Step 5: Implementing Server Logic (Load & Actions)

SvelteKit uses +page.server.ts to handle data fetching and form submissions.

The Load Function (Fetching Data)

export const load = async ({ locals }) => {
    const todos = await locals.db.select().from(todo);
    return { todos };
};

Form Actions (Mutating Data)

export const actions = {
    create: async ({ request, locals }) => {
        const formData = await request.formData();
        const text = formData.get('text');
        await locals.db.insert(todo).values({ text });
        return { success: true };
    },
    // ... update and delete actions
};

Step 6: The "Flat Comic" UI

Now for the fun part! We'll use Svelte 5 runes and Tailwind CSS to build a UI that looks like a comic book panel.

In src/routes/+page.svelte:

<script lang="ts">
    import { enhance } from '$app/forms';
    let { data } = $props();
</script>

<div class="p-8 bg-cyan-50 min-h-screen font-mono">
    <!-- Header with Neubrutalist Style -->
    <h1 class="text-6xl font-black bg-yellow-400 border-4 border-black shadow-[8px_8px_0px_0px_rgba(0,0,0,1)] px-4 py-2 -rotate-2 inline-block">
        MY COMIC BLOG
    </h1>

    <!-- Create Card -->
    <section class="mt-12 bg-white border-4 border-black shadow-[8px_8px_0px_0px_rgba(0,0,0,1)] p-6 mb-8 uppercase italic font-bold">
        <form method="POST" action="?/create" use:enhance>
            <input name="text" class="w-full border-4 border-black p-4 text-xl" placeholder="Write something..."/>
            <button class="mt-4 bg-rose-400 border-4 border-black p-4 shadow-[4px_4px_0px_0px_rgba(0,0,0,1)] active:translate-x-1 active:translate-y-1 active:shadow-none transition-all">
                POW! ADD IT!
            </button>
        </form>
    </section>

    <!-- List Panels -->
    <div class="grid gap-6">
        {#each data.todos as item}
            <article class="bg-white border-4 border-black shadow-[8px_8px_0px_0px_rgba(0,0,0,1)] p-6">
                <p class="text-2xl font-black">{item.text}</p>
            </article>
        {/each}
    </div>
</div>

Why this Stack?

  1. SvelteKit: Simplifies the boundary between client and server.
  2. Drizzle ORM: Unlike heavy ORMs, Drizzle is "thin" and extremely fast on Cloudflare Workers.
  3. Cloudflare D1: Provides a global, low-latency SQL database that integrates perfectly with the Cloudflare ecosystem.
  4. Tailwind CSS: Makes implementing hyper-specific design systems like Neubrutalism straightforward.

Conclusion

Building with SvelteKit and Drizzle on Cloudflare D1 is a developer experience dream. You get full type safety from your database to your UI, incredible performance at the edge, and the freedom to style your app with unique aesthetics like the "Flat Comic" look.

Ready to deploy? Just run pnpm wrangler deploy and your comic blog is live!

Top categories

Loading Svelte Themes