Tutorial: integrate Sentry into your GitHub Actions deploy pipeline — automatic source map upload & issue creation (PHP & JavaScript)
Ferramentas & Produtividade · By Kevin Marcondes · Published on · 9 min read
This tutorial shows how to integrate Sentry into your GitHub Actions deploy pipeline to automatically upload source maps and create issues for PHP and JavaScript. You’ll create releases, upload frontend source maps in CI, and tag both frontend and backend with the same release so stack traces are readable and correlated with deploy commits.
Prerequisites and what you’ll configure
You’ll build a CI/CD flow that registers a release in Sentry, uploads frontend source maps, and tags the PHP backend with the release. At the end, any production exception becomes a Sentry issue with an unobfuscated stack trace associated with the deploy commit.
What you need before starting:
- A Sentry account and project (organization slug and project slug).
- A Sentry DSN for the frontend (public) and the backend (server).
- A SENTRY_AUTH_TOKEN with releases permissions.
- A GitHub repository with GitHub Actions enabled.
- A JS project that generates source maps (Vite or Webpack) and a PHP backend with the Sentry SDK.
Configure Sentry in JavaScript and generate build source maps
Initialize the Sentry SDK in your JS app and ensure the bundler generates production source maps. A source map maps minified JavaScript back to the original source so stack traces are readable. MDN has a good explanation of the concept.
Set the release and environment variables from the pipeline (for example, via Vite). Do NOT publish .map files to your CDN; we’ll upload them to Sentry in CI.
// Instale o SDK do browser
// npm i @sentry/browser --save
// src/sentry.ts (ou no bootstrap do app)
import * as Sentry from "@sentry/browser";
Sentry.init({
dsn: import.meta.env.VITE_SENTRY_DSN, // DSN público do projeto
release: import.meta.env.VITE_RELEASE, // versão injetada pelo CI
environment: import.meta.env.MODE || "production",
});
// Exemplo: capturar erro manual (para teste)
// Sentry.captureException(new Error("Sentry JS test error"));
// vite.config.ts (Vite) — habilite sourcemap em produção
// import { defineConfig } from "vite";
// export default defineConfig({
// build: { sourcemap: true },
// });
// webpack.config.js (Webpack) — alternativa
// module.exports = {
// // ...
// devtool: "source-map", // gera .map para produção
// };
PHP: install the SDK and mark release/environment in bootstrap
On the PHP backend, install the SDK and initialize it with the DSN, release and environment. This ensures server exceptions are attributed to the same release as the frontend. Frameworks may provide integrations; the example below works in any PHP app.
To capture unhandled exceptions, use the SDK’s default handler or integrate with your framework. Do NOT log sensitive tokens in exceptions.
<?php
// Instale o SDK PHP (Composer):
// composer require sentry/sdk
require_once __DIR__ . '/vendor/autoload.php';
Sentry\init([
'dsn' => getenv('SENTRY_DSN'),
'release' => getenv('RELEASE') ?: getenv('SENTRY_RELEASE'),
'environment' => getenv('ENVIRONMENT') ?: 'production',
]);
// Exemplo de teste
// try {
// throw new Exception('Sentry PHP test error');
// } catch (Throwable $e) {
// Sentry\captureException($e);
// }
Which secrets and variables to use in GitHub Actions?
Create repository secrets for the Sentry token and the organization/project slugs. Release and environment variables can be set as workflow env. Do NOT expose SENTRY_AUTH_TOKEN in logs.
| Key | Type | Purpose |
|---|---|---|
| SENTRY_AUTH_TOKEN | Secret | Authenticate sentry-cli for releases and source map uploads |
| SENTRY_ORG | Secret | Sentry organization slug |
| SENTRY_PROJECT | Secret | Sentry project slug |
| SENTRY_DSN_PUBLIC | Secret | Public DSN for the frontend (injected into the build) |
| SENTRY_DSN | Secret | Server DSN for PHP (configured in infrastructure) |
| RELEASE | Env | Deploy version (e.g. GITHUB_SHA or a tag) |
| ENVIRONMENT | Env | Deploy environment (e.g. production, staging) |
GitHub Actions pipeline: build, release and automatic source map upload
The workflow below creates a Sentry release, associates commits, uploads the source maps generated by your bundler, and finalizes the release. It also injects RELEASE and the public DSN into the frontend build so events are correctly tagged.
If your deploy has extra steps (canary, smoke tests, rollback), integrate this into your existing pipeline. Examples: Canary deploys with GitHub Actions and Nginx/ PHP and a pipeline with rollback and smoke tests.
name: deploy
on:
push:
branches: ["main"]
env:
RELEASE: ${{ github.sha }}
ENVIRONMENT: production
jobs:
build-and-release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # necessário para set-commits --auto
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install deps
run: npm ci
- name: Build (inject release and DSN)
run: |
echo "VITE_RELEASE=${RELEASE}" >> .env
echo "VITE_SENTRY_DSN=${{ secrets.SENTRY_DSN_PUBLIC }}" >> .env
npm run build
- name: Install sentry-cli
run: npm i -g @sentry/cli
- name: Create release in Sentry
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
run: |
sentry-cli releases new "$RELEASE"
sentry-cli releases set-commits "$RELEASE" --auto
- name: Upload source maps to Sentry
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
run: |
# Ajuste o caminho conforme seu bundler (ex.: dist, build)
sentry-cli releases files "$RELEASE" upload-sourcemaps ./dist \
--url-prefix "~/" \
--validate --rewrite
- name: Finalize release
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
run: sentry-cli releases finalize "$RELEASE"
- name: Deploy
run: |
# Execute seu deploy (ex.: rsync, kubectl, serverless, etc.)
echo "Deploy step here"
How to mark the same release in the PHP backend during deploy
The backend must receive the same RELEASE and ENVIRONMENT variables used in the workflow. You can write these variables into the server .env, the container manifest, or the service manager (e.g. systemd, ECS). PHP will read them at bootstrap so events are sent with the correct version.
- Persist RELEASE and ENVIRONMENT in the service configuration.
- Restart PHP/FPM after changing variables.
- Ensure the server DSN (SENTRY_DSN) is configured in the host, container, or secret manager.
# Exemplo simples: escrever variáveis em um .env no servidor durante o deploy
# (substitua /var/www/app pelo caminho do seu app)
ssh user@host "echo 'RELEASE=${RELEASE}' | sudo tee -a /var/www/app/.env && \
echo 'ENVIRONMENT=${ENVIRONMENT}' | sudo tee -a /var/www/app/.env && \
sudo systemctl restart php-fpm"
How to verify it worked (post-deploy checks)
Validate the integration by generating a test exception in the frontend and backend. Within seconds, Sentry should create issues with the correct release and environment, and the JS stack trace should be de-obfuscated thanks to the source maps.
Run tests only in a controlled environment and remove the test code after validation.
- Check in Sentry that events are tied to the correct release.
- Confirm the JS stack trace points to original files/lines.
- Verify the environment matches production or staging.
# Frontend (abra o console do navegador após o deploy)
// window.Sentry.captureException(new Error("Sentry JS test after deploy"));
# Backend PHP (rota temporária)
<?php
// /debug/sentry-test (remova depois)
throw new Exception('Sentry PHP test after deploy');
Common troubleshooting
Events show up without a release? Ensure RELEASE was injected into the frontend build and is available to the PHP bootstrap. The value must match the one used with sentry-cli releases.
Source maps not applying? The url-prefix must match how your app serves assets in production. If assets are under /static or a CDN, adjust the prefix. Do NOT publish .map files publicly; keep them private and upload only to Sentry.
Invalid token or insufficient permissions? Recreate SENTRY_AUTH_TOKEN with release scopes in Sentry. Do not print the token in logs. Use GitHub Secrets.
Build removes .map files? Check bundler config (Vite: build.sourcemap=true; Webpack: devtool=source-map). MDN has a guide on source maps.
Commits don't appear in the release? Make sure the repo was checked out with history (fetch-depth: 0) before set-commits, or provide the commit range manually to sentry-cli. In monorepos, target the correct project.
Frequently asked questions
Do I need to expose the DSN in the frontend?
Yes. The browser SDK uses a public DSN to send events. This DSN doesn’t grant administrative access. The server DSN must remain protected. Never expose SENTRY_AUTH_TOKEN, which is used only in CI for releases and source map uploads.
How should I set the release automatically in CI?
Use a repository-derived identifier like GITHUB_SHA, a semantic tag, or a short hash. The important part is using the same value with sentry-cli releases, in the frontend build, and in the backend configuration so events map to the same release.
Where should source maps live: Sentry or the CDN?
You only need to upload source maps to Sentry via CI/CD for Sentry to de-obfuscate stack traces. They don’t need to be public on the CDN. Keeping .map files private avoids exposing source code. Just make sure url-prefix and paths match your production assets.
What permissions does the Sentry token need for uploads?
SENTRY_AUTH_TOKEN must allow creating and editing releases and uploading files. Create it in Sentry with the appropriate scopes and store it in GitHub Secrets. Limit scope to the organization/project and rotate tokens periodically.
Can I use the official action instead of sentry-cli via npm?
Yes. There are Actions that simplify creating releases, setting commits, uploading source maps, and finalizing releases. The secrets and variables remain the same. Use an Action to reduce shell steps in the workflow if you prefer.
Does this work with monorepos and multiple Sentry projects?
Yes, but run sentry-cli per project where you want to publish a release and source maps, setting the correct SENTRY_PROJECT. Adjust build directories per app and keep releases consistent between services to maintain correlation between frontend and backends.
Want to improve your pipeline with practical observability?
Integrate releases, source maps, and fast regression detection into your CI/CD. If you use GitHub Actions and want to add canary deploys, smoke tests and rollback, follow the suggested guides and implement it today.
Explore more tutorialsSee also
- Tutorial: set up mTLS between Traefik and Docker Compose services using smallstep CA and automatic certificates — step by step
- Configure retention and compression for Docker container logs with journald + logrotate + rsyslog on a low-disk VPS
- Tutorial: Configure GitHub Actions for integration tests with PostgreSQL in ephemeral containers and automatic migration rollback — a practical guide
- Configure BuildKit garbage collection and systemd timers to auto‑clean Docker images and volumes: a practical tutorial