Skip to main content
The Sentry Astro SDK provides error monitoring and performance tracking for Astro applications with support for both client and server-side rendering.
The Astro SDK is currently in Beta. Features and APIs may change. Please report any issues on GitHub.

Installation

1

Install with Astro CLI

The easiest way to add Sentry to your Astro project:
npx astro add @sentry/astro
This will:
  • Install the @sentry/astro package
  • Add the integration to astro.config.mjs
  • Set up automatic instrumentation
2

Manual Installation

npm install @sentry/astro

Version Compatibility

  • Astro 3.5.2+: Automatic server instrumentation
  • Astro 3.0+: Manual middleware setup required
  • Works with SSR and static site generation

Basic Setup

Astro Configuration

Add Sentry to your astro.config.mjs:
import { defineConfig } from 'astro/config';
import sentry from '@sentry/astro';

export default defineConfig({
  integrations: [
    sentry({
      dsn: 'YOUR_DSN_HERE',
      sourceMapsUploadOptions: {
        project: 'your-project',
        authToken: process.env.SENTRY_AUTH_TOKEN,
      },
    }),
  ],
  output: 'server', // or 'hybrid'
});

Client Initialization

Create src/sentry.client.config.ts:
import * as Sentry from '@sentry/astro';

Sentry.init({
  dsn: 'YOUR_DSN_HERE',
  
  // Performance Monitoring
  tracesSampleRate: 1.0,
  
  // Session Replay
  replaysSessionSampleRate: 0.1,
  replaysOnErrorSampleRate: 1.0,
  
  integrations: [
    Sentry.replayIntegration(),
  ],
});

Server Initialization

Create src/sentry.server.config.ts:
import * as Sentry from '@sentry/astro';

Sentry.init({
  dsn: 'YOUR_DSN_HERE',
  tracesSampleRate: 1.0,
});

Server-Side Instrumentation

Automatic (Astro 3.5.2+)

For Astro 3.5.2+, server instrumentation is automatic. No middleware setup needed.

Manual (Astro versions below 3.5.2)

For older versions, create src/middleware.ts:
import { sequence } from 'astro:middleware';
import * as Sentry from '@sentry/astro';

export const onRequest = sequence(
  Sentry.handleRequest(),
  // Add your other middleware here
);

Disable Automatic Instrumentation

If you want to opt out:
// astro.config.mjs
export default defineConfig({
  integrations: [
    sentry({
      dsn: 'YOUR_DSN_HERE',
      autoInstrumentation: {
        requestHandler: false,
      },
    }),
  ],
});

Error Handling

API Routes

// src/pages/api/users.ts
import type { APIRoute } from 'astro';
import * as Sentry from '@sentry/astro';

export const GET: APIRoute = async ({ params }) => {
  try {
    const users = await fetchUsers();
    return new Response(
      JSON.stringify(users),
      { status: 200 }
    );
  } catch (error) {
    Sentry.captureException(error);
    return new Response(
      JSON.stringify({ error: 'Internal Server Error' }),
      { status: 500 }
    );
  }
};

Server-Side Rendering

---
// src/pages/user/[id].astro
import * as Sentry from '@sentry/astro';

const { id } = Astro.params;

let user;
try {
  user = await fetchUser(id);
} catch (error) {
  Sentry.captureException(error);
  return Astro.redirect('/404');
}
---

<html>
  <body>
    <h1>{user.name}</h1>
  </body>
</html>

Client-Side Components

---
// src/components/Button.astro
---

<button id="my-button">Click me</button>

<script>
  import * as Sentry from '@sentry/astro';
  
  document.getElementById('my-button')?.addEventListener('click', async () => {
    try {
      await riskyOperation();
    } catch (error) {
      Sentry.captureException(error);
    }
  });
</script>

Performance Monitoring

Custom Spans

import * as Sentry from '@sentry/astro';

export async function fetchData() {
  return await Sentry.startSpan(
    {
      name: 'fetch-data',
      op: 'function',
    },
    async () => {
      const response = await fetch('/api/data');
      return response.json();
    },
  );
}

Database Queries

import * as Sentry from '@sentry/astro';
import { db } from './db';

export async function getUser(id: string) {
  return await Sentry.startSpan(
    {
      name: 'db.query.user',
      op: 'db.query',
      attributes: {
        'db.system': 'postgresql',
        'db.operation': 'SELECT',
      },
    },
    async () => {
      return await db.user.findUnique({ where: { id } });
    },
  );
}

Context and User Information

Setting Context in API Routes

// src/pages/api/protected.ts
import type { APIRoute } from 'astro';
import * as Sentry from '@sentry/astro';

export const GET: APIRoute = async ({ request, cookies }) => {
  const userId = cookies.get('user_id')?.value;
  
  if (userId) {
    Sentry.setUser({ id: userId });
  }
  
  Sentry.setContext('request', {
    method: request.method,
    url: request.url,
  });
  
  // Your route logic
};

Client-Side User Context

---
// src/layouts/Layout.astro
const user = Astro.locals.user;
---

<html>
  <head>
    <script define:vars={{ user }}>
      if (user) {
        import('@sentry/astro').then(Sentry => {
          Sentry.setUser({
            id: user.id,
            email: user.email,
          });
        });
      }
    </script>
  </head>
  <body>
    <slot />
  </body>
</html>

Source Maps Upload

Configuration

// astro.config.mjs
import { defineConfig } from 'astro/config';
import sentry from '@sentry/astro';

export default defineConfig({
  integrations: [
    sentry({
      dsn: 'YOUR_DSN_HERE',
      sourceMapsUploadOptions: {
        project: 'your-project',
        authToken: process.env.SENTRY_AUTH_TOKEN,
        org: 'your-org',
      },
    }),
  ],
});

Environment Variables

Create a .env file:
# Required
SENTRY_DSN=your-dsn-here

# For source maps
SENTRY_AUTH_TOKEN=your-auth-token

# Optional
SENTRY_ENVIRONMENT=production
SENTRY_RELEASE=1.0.0

Framework Integrations

React Integration

---
// src/components/ReactComponent.tsx
import { useState } from 'react';
import * as Sentry from '@sentry/astro';

export default function Counter() {
  const [count, setCount] = useState(0);
  
  const handleClick = () => {
    try {
      // Your logic
      setCount(count + 1);
    } catch (error) {
      Sentry.captureException(error);
    }
  };
  
  return <button onClick={handleClick}>Count: {count}</button>;
}
---

<html>
  <body>
    <Counter client:load />
  </body>
</html>

Vue Integration

<!-- src/components/VueComponent.vue -->
<script setup lang="ts">
import * as Sentry from '@sentry/astro';
import { ref } from 'vue';

const count = ref(0);

const handleClick = () => {
  try {
    count.value++;
  } catch (error) {
    Sentry.captureException(error);
  }
};
</script>

<template>
  <button @click="handleClick">Count: {{ count }}</button>
</template>

Deployment

Add environment variables in Vercel:
  • SENTRY_DSN
  • SENTRY_AUTH_TOKEN

Best Practices

SSR Configuration

Configure both client and server for full coverage.

Middleware Order

Place Sentry.handleRequest() first in middleware sequence.

Source Maps

Always upload source maps for production deployments.

Error Boundaries

Use try-catch in API routes and page components.

Troubleshooting

For Astro versions below 3.5.2:
  1. Ensure src/middleware.ts exists
  2. Verify Sentry.handleRequest() is called
  3. Check that output is ‘server’ or ‘hybrid’
Verify:
  1. SENTRY_AUTH_TOKEN is set
  2. sourceMapsUploadOptions is configured
  3. Build completes successfully

Next Steps

API Routes

Monitor API endpoint performance

SSR Pages

Track server-rendered pages

Session Replay

Debug with session recordings

Adapters

Configure for your deployment platform

Build docs developers (and LLMs) love