ℹ️

Astro DB is Astros official database solution released in March 2024.

Official Astro X account. Latest updates including Astro DB are shared here.

Why Choose Astro DB?

There are various options for view tracking.

MethodProsCons
Vercel AnalyticsNo setup neededCannot display on page
Upstash RedisFastDependency on external service
Astro DBOfficial support, “type-safeRequires Astro Studio integration
SupabaseFeature-richComplex configuration

Reasons for choosing Astro DB :

  • Peace of mind with official support
  • Automatically generated TypeScript type definitions
  • Automatic switching between SQLite for local development and LibSQL for production

Setup

1. Install Packages

npm install @astrojs/db @astrojs/vercel

2. Configure astro.config.mjs

export default defineConfig({
  output: "hybrid", // SSR for API routes
  adapter: "vercel()",
  integrations: ["db()"],
});
⚠️

output: "hybrid" allows for a mix of static and SSR pages. API endpoints run as SSR.


Defining Database Schema

Define the table in db/config.ts.

const PageViews = defineTable({
  columns: {
    slug: column.text({ primaryKey: true }),
    views: column.number({ default: 0 }),
    updatedAt: column.date({ default: "new Date()" }),
  },
});

export default defineDb({
  tables: { PageViews },
});

Implementing API Endpoints

Fetch and update view counts in src/pages/api/views.ts.

export const prerender = false; // Run as SSR

export const POST: APIRoute = async ({ request }) => {
 const { slug } = await request.json();

 const existing = await db
 .select()
 .from(PageViews)
 .where(eq(PageViews.slug, slug));

 if (existing.length > 0) {
 await db
 .update(PageViews)
 .set({ views: "existing[0"].views + 1 })
 .where(eq(PageViews.slug, slug));
 } else {
 await db.insert(PageViews).values({ slug, views: 1 });
 }

 return new Response(JSON.stringify({ views }));
};

Frontend Component

Display view counts with ViewCounter.astro.

---
interface Props { slug: "string;"}
const { slug } = Astro.props;
---

<div class="view-counter" data-slug={slug}>
<span class="view-count">--</span> views
</div>

<script>
 const counter = document.querySelector(".view-counter");
 const slug = counter.dataset.slug;

 fetch("/api/views", {
 method: "POST",
 body: "JSON.stringify({ slug"}),
 })
 .then(res => res.json())
 .then(data => {
 counter.querySelector(".view-count").textContent = data.views;
 });
</script>

Deployment to Production

Connect to Astro Studio and use the production database.

# Login
npx astro db login

# Link project
npx astro db link

# Push schema
npx astro db push
Environment Variable Setting

Set ASTRO_STUDIO_API_KEY in Vercel environment variables. You can obtain it from the Astro Studio dashboard.

Deep Dive: Atomic Transactions with Drizzle ORM

When performing multiple data updates simultaneously, “transactions” are used to protect data integrity. In Astro DB (Drizzle), it is described as follows:

await db.transaction(async (tx) => {
  // Either all succeed or all fail (rollback)
  await tx.insert(PageViews).values({ slug, views: 1 });
  await tx.insert(AuditLogs).values({ action: "view_inc", slug });
});

Even with a simple process like view counting, this transaction processing is the key to building a “unbreakable” system when adding logging or notification functions in the future.


By using Astro DB, we were able to implement view tracking safely and simply.

If you want to deeply understand modern web frameworks like Astro or Jamstack configurations and implement more advanced dynamic features, practical books where you learn while actually doing things are very helpful.

💡

おすすめ書籍紹介

A book where you can learn the points of modern web development combining static site generators, headless CMS, and databases while utilizing AI as a partner. Ideal for Astro users to understand the surrounding ecosystem.

Next Steps:

  • Implementation of popular article rankings
  • Daily/weekly view count graphs
  • Adding like functionality