What is D1?
D1 is Cloudflare’s serverless SQL database. Under the hood, it’s SQLite — you get full SQL support, but it runs at the edge alongside your Worker. There’s no connection string, no VPN, no cold start penalty. Your Worker accesses D1 through a binding, which means it’s available as env.INCIDENTS_DB in your code with zero network hops.
Why D1 here? The incident queue needs structured data: incident IDs, titles, severity levels, timestamps, alert types, and raw telemetry payloads. D1 gives you a real SQL database for this without any infrastructure management.
D1 data flow: Worker to incident queue
flowchart LR W[Worker] -->|env.INCIDENTS_DB| D1[(D1 Database)] D1 --> T[incidents table] T --> id[incident_id] T --> title[title] T --> sev[severity] T --> typ[type] T --> ts[created_at] T --> tel[telemetry] D1 -->|SQL query| W W -->|JSON response| UI[UI Incident Queue]
Step 1: Create the D1 database
From inside your sirt-workshop-app/ directory, run:
npx wrangler d1 create sirt-incidents
The output will look like:
✅ Successfully created DB 'sirt-incidents' in region WNAM
Created your new D1 database.
[[d1_databases]]
binding = "INCIDENTS_DB"
database_name = "sirt-incidents"
database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
Copy the database_id value. You’ll need it in the next step.
Step 2: Add the D1 binding to wrangler.jsonc
Open sirt-workshop-app/wrangler.jsonc in your editor. Find the commented-out d1_databases block — it looks something like this:
// Uncomment for lesson 06:
// "d1_databases": [
// {
// "binding": "INCIDENTS_DB",
// "database_name": "sirt-incidents",
// "database_id": "<your-database-id>"
// }
// ]
Uncomment the block and replace <your-database-id> with the actual database_id from Step 1:
"d1_databases": [
{
"binding": "INCIDENTS_DB",
"database_name": "sirt-incidents",
"database_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
]
Step 3: Run the seed migration
The workshop app includes a pre-written migration file at migrations/001-seed.sql. This file creates an incidents table and inserts four sample incidents matching the scenarios from lesson 02.
Run the migration against your remote D1 database:
npx wrangler d1 execute sirt-incidents --remote --file=migrations/001-seed.sql
The --remote flag is important — it runs the migration on your deployed D1 database, not a local copy.
You should see output confirming the SQL was executed successfully. The migration creates the incidents table with columns for:
id— unique incident identifiertitle— human-readable incident nametype— alert category (malware, phishing, auth_anomaly, data_exfiltration)severity— initial severity ratingstatus— current status (new, investigating, triaged, closed)created_at— timestamptelemetry— JSON blob with raw alert data specific to each scenario
The four seeded incidents are:
- Malware + C2 Beacon — Encoded PowerShell, C2 IP communication
- Phishing + BEC — Credential harvesting click, mailbox forwarding rule
- Anomalous Authentication — Service account, impossible travel, 3 countries in 10 min
- Data Exfiltration — Off-hours upload to unapproved cloud storage
Step 4: Change STATE to state-2-d1
In wrangler.jsonc, find the STATE variable and update it:
"vars": {
"STATE": "state-2-d1"
}
This tells the app to fetch incidents from D1 instead of showing the empty state message. The queue component will query env.INCIDENTS_DB and render a card for each row in the incidents table.
Step 5: Redeploy and verify
Deploy the updated configuration:
npx wrangler deploy
Now reload your app in the browser. Instead of “No incidents yet,” you should see four incident cards in the queue, each showing:
- The incident title
- The severity level (critical, high, medium)
- The alert type
- The timestamp
Click on an incident to see its detail view. At this stage, the detail view shows raw telemetry data but no analysis — that comes in later lessons when you add Workers AI and the agent harness.