sanic-org/sanic
Accelerate your web app development | Build fast. Run fast.
Healthy across the board
weakest axisPermissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 4w ago
- ✓33+ active contributors
- ✓MIT licensed
- ✓CI configured
- ✓Tests present
- ⚠Concentrated ownership — top contributor handles 55% of recent commits
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/sanic-org/sanic)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/sanic-org/sanic on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: sanic-org/sanic
Generated by RepoPilot · 2026-05-07 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/sanic-org/sanic shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across the board
- Last commit 4w ago
- 33+ active contributors
- MIT licensed
- CI configured
- Tests present
- ⚠ Concentrated ownership — top contributor handles 55% of recent commits
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live sanic-org/sanic
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/sanic-org/sanic.
What it runs against: a local clone of sanic-org/sanic — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in sanic-org/sanic | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch main exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 57 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of sanic-org/sanic. If you don't
# have one yet, run these first:
#
# git clone https://github.com/sanic-org/sanic.git
# cd sanic
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of sanic-org/sanic and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "sanic-org/sanic(\\.git)?\\b" \\
&& ok "origin remote is sanic-org/sanic" \\
|| miss "origin remote is not sanic-org/sanic (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
&& ok "default branch main exists" \\
|| miss "default branch main no longer exists"
# 4. Critical files exist
test -f "sanic/__init__.py" \\
&& ok "sanic/__init__.py" \\
|| miss "missing critical file: sanic/__init__.py"
test -f "sanic/app.py" \\
&& ok "sanic/app.py" \\
|| miss "missing critical file: sanic/app.py"
test -f "sanic/router.py" \\
&& ok "sanic/router.py" \\
|| miss "missing critical file: sanic/router.py"
test -f "sanic/request.py" \\
&& ok "sanic/request.py" \\
|| miss "missing critical file: sanic/request.py"
test -f "sanic/response.py" \\
&& ok "sanic/response.py" \\
|| miss "missing critical file: sanic/response.py"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 57 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~27d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/sanic-org/sanic"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
Sanic is a Python 3.10+ async web framework and ASGI-compliant server designed for high-performance request handling using async/await syntax. It enables developers to build fast, non-blocking web applications with minimal boilerplate while maintaining compatibility with the ASGI standard for deployment flexibility. The repo is organized as a monorepo-style structure: core framework code lives in the root sanic/ package (implied by file structure), docs/ contains Sphinx-based documentation with API references (docs/sanic/api/), docker/ provides containerized deployment, and changelogs/ tracks incremental feature delivery. CI workflows orchestrate testing across Python versions via .github/workflows/.
👥Who it's for
Python backend engineers and DevOps teams building real-time, I/O-bound web applications and microservices who need sub-millisecond response times without the complexity of traditional threaded servers. Contributors are typically framework maintainers and Pythonistas optimizing async server performance.
🌱Maturity & risk
Sanic is production-ready and actively maintained: the repo shows 1.89M lines of Python code with comprehensive test coverage (coverage.yml workflow), CI/CD via GitHub Actions (tests.yml, codeql-analysis.yml), and documented changelogs (changelogs/ directory with entries for v23.12+). The framework requires Python 3.10+ minimum and maintains regular release cycles with security scanning.
Low to moderate risk: the dependency footprint is lean (msgspec, python-frontmatter, pygments, libsass, mistune for docs/tooling), but the framework maintains strict Python version requirements (3.10+) which could limit adoption in legacy environments. The fast-moving async ecosystem means occasional breaking changes (evident from CHANGELOG.md and removal entries in changelogs/), so upgrade testing is critical. Single-domain expertise concentration in ASGI/async patterns could create knowledge silos.
Active areas of work
Active development visible in changelogs/ with recent entries (1892.removal.rst, 1904.feature.rst, 1970.misc.rst) indicating ongoing feature work and API refinements. GitHub Actions workflows show continuous testing, code quality analysis (CodeQL), and release publishing automation, with coverage tracking and conditional deployment pipelines.
🚀Get running
git clone https://github.com/sanic-org/sanic.git
cd sanic
pip install -e .
pip install sanic-ext msgspec python-frontmatter pygments docstring-parser libsass mistune
make test
Daily commands:
python -m sanic your_app:app --host=0.0.0.0 --port=8000
For development, use the Makefile: make shows available targets. Refer to docs/Makefile for documentation builds.
🗺️Map of the codebase
sanic/__init__.py— Main entry point exporting the Sanic app class and core APIs that all developers use to build applications.sanic/app.py— Core Sanic application class containing request routing, middleware management, and server lifecycle—the foundation of the framework.sanic/router.py— URL routing engine that maps HTTP requests to handlers; critical for understanding request dispatch and parameter extraction.sanic/request.py— Request object abstraction encapsulating HTTP headers, body, query parameters, and context—used by every route handler.sanic/response.py— Response object and factory functions that serialize handler output back to clients; essential for understanding Sanic's HTTP contract.sanic/server.py— Low-level server management including event loop setup, signal handling, and protocol initialization for async request processing.CONTRIBUTING.md— Project contribution guidelines, code style, and development workflow that all contributors must follow.
🧩Components & responsibilities
- Sanic App (sanic/app.py) (asyncio, signal handling, dict-based config) — Orchestrates route registration, middleware chains, server startup/shutdown, and request delegation to handlers.
- Failure mode: Unhandled exceptions in route handlers propagate; middleware chain breaks unless errors caught explicitly.
- Router (sanic/router.py) (Trie data structure, regex for dynamic segments) — Matches incoming HTTP requests to registered route patterns; extracts path parameters and query args.
- Failure mode: 404 Not Found if no route matches; parameter extraction fails silently if pattern malformed.
- Request/Response (sanic/request.py, sanic/response.py) (asyncio streams, json/msgspec encoders, aiofiles for file I/O) — Abstracts HTTP message parsing and serialization; provides handlers convenient access to headers, body, cookies.
- Failure mode: Malformed request bodies or oversized payloads rejected; streaming interrupted if client disconnects.
- Server (sanic/server.py) (asyncio.Protocol, socket binding, signal handlers) — Creates and manages HTTP protocol handlers, binds to sockets, oversees event loop lifecycle and graceful shutdown.
- Failure mode: Port binding fails if already in use; event loop crashes if unhandled exception in async code; graceful shutdown may timeout.
- Middleware (sanic/middleware.py) (Decorator pattern, async/) — Chains request and response processors around handlers; enables logging, security, CORS, compression.
🛠️How to make changes
Add a new HTTP route handler
- Open or create your application file with a Sanic instance (
examples/hello_world.py) - Use the @app.route() decorator with HTTP method and path pattern to register handler (
sanic/app.py) - Define an async handler function that receives a Request and returns a Response (
sanic/response.py) - Run app.run() to start the async server on localhost (
sanic/server.py)
Create a new Blueprint for modular routes
- Import Blueprint and instantiate with a name and url_prefix (
sanic/blueprints.py) - Register routes on the blueprint using @bp.route() decorator (same as app) (
examples/blueprints.py) - Register the blueprint to your app via app.blueprint(bp) in main application file (
sanic/app.py)
Add middleware for request/response processing
- Define an async middleware function that receives request, calls await continuation, and optionally modifies response (
sanic/middleware.py) - Register with @app.middleware('request') or @app.middleware('response') decorator (
sanic/app.py) - Middleware will execute in registration order before/after all matching route handlers (
examples/blueprint_middlware_execution_order.py)
Handle custom exceptions and errors
- Define a custom exception class inheriting from sanic.exceptions.SanicException (
sanic/exceptions.py) - Register error handler with @app.exception(CustomException) decorator (
sanic/app.py) - Handler receives request and exception; return a Response to customize error page/JSON (
examples/exception_monitoring.py)
🔧Why these technologies
- asyncio (Python async/await) — Non-blocking I/O for handling thousands of concurrent connections efficiently without threads; native Python async paradigm.
- Uvloop (optional drop-in replacement) — Faster event loop implementation for production deployments, 2-4x faster than default asyncio.
- Trie-based routing — O(1) route lookup for fast request dispatch without regex compilation overhead.
- msgspec (dependencies) — Fast JSON serialization/deserialization for request/response bodies in production.
⚖️Trade-offs already made
-
Async-only design (no sync support)
- Why: Simplifies codebase, leverages modern Python async ecosystem, and enables high concurrency.
- Consequence: All route handlers, middleware, and extensions must be async; can't use blocking libraries (e.g., requests) without thread pool workaround.
-
Single-process default with optional multiprocessing
- Why: Async already handles concurrency within one process; keeps deployment simple.
- Consequence: Single CPU core per process by default; must spawn multiple workers for multi-core scaling (managed separately or via supervisor).
-
Minimal built-in ORM/DB abstractions
- Why: Keeps framework lightweight and lets users choose their own DB driver (asyncpg, motor, sqlalchemy).
- Consequence: Developers must integrate third-party database libraries; no batteries-included SQL toolkit unlike Django.
🚫Non-goals (don't propose these)
- Does not provide built-in database ORM (use sqlalchemy, tortoise-orm, or asyncpg directly)
- Does not include authentication/authorization out of the box (use sanic-ext or third-party middleware)
- Not a full-stack web framework (no templates, form validation, admin panels—focus is HTTP server)
- Does not support Windows as first-class deployment target (asyncio signal handling limited on Windows)
🪤Traps & gotchas
async/await is mandatory — synchronous request handlers are not supported; this breaks ported code from Flask/Django without refactoring. Python 3.10+ minimum is strictly enforced (no 3.9 backport support). ASGI compliance means certain deployment assumptions differ from traditional WSGI servers; test against your actual ASGI server (Uvicorn, Hypercorn, etc.) in staging. Middleware execution order and exception handling in async contexts can be non-intuitive — review middleware-specific docs carefully.
🏗️Architecture
💡Concepts to learn
- ASGI (Asynchronous Server Gateway Interface) — Sanic is ASGI-compliant, which determines how it integrates with production servers (Uvicorn, Hypercorn) and middleware ecosystems; understanding ASGI contracts is essential for deploying beyond the development server
- Async/Await and asyncio Event Loop — Sanic's entire programming model depends on async/await syntax and the asyncio event loop; debugging performance issues and understanding concurrency limits requires deep knowledge of event loop behavior and task scheduling
- Middleware Pipeline and Request/Response Lifecycle — Sanic's decorator-based middleware system and handler execution order are non-obvious in async context; incorrectly ordered middleware or blocking operations in handlers can destroy performance gains
- Blueprint Modularization — Large Sanic applications use blueprints (visible in docs/sanic/api/blueprints.rst) to organize routes and middleware; understanding blueprint registration order and scope is critical for avoiding route conflicts and middleware duplication
- Message Pack Serialization (msgspec) — Sanic defaults to msgspec for fast serialization of request/response bodies; performance-sensitive applications must understand its incompatibilities with pickle and JSON edge cases
- Structured Concurrency and Task Management — Background tasks and concurrent operations within Sanic handlers require careful use of asyncio primitives (create_task, gather, TaskGroup); improper task lifecycle management causes resource leaks and silent failures
- Request Context and App Context (Lifespan) — Sanic's app.ctx and request.ctx objects are how state is passed through the async request lifecycle; context isolation bugs in concurrent environments are hard to debug and lead to data races
🔗Related repos
encode/starlette— Similar ASGI-first async web framework in Python; direct competitor with emphasis on simplicity and compatibility with existing ASGI middleware ecosystemtiangolo/fastapi— Higher-level async framework built on Starlette; widely adopted for API development and automatic OpenAPI doc generation, appeals to overlapping developer audiencedjango/django— Traditional Python web framework with async support added in recent versions; many Sanic users evaluate it as a heavier alternative for monolithic applicationssanic-org/sanic-ext— Official extension library providing OpenAPI/Swagger integration, authentication, and validation plugins that extend base Sanic framework capabilitiespython-trio/trio— Structured concurrency runtime alternative to asyncio; relevant context for understanding Sanic's design decisions and async Python ecosystem positioning
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive test coverage for changelog entry validation in changelogs/
The repo uses a changelog management system (changelogs/ directory with .removal.rst, .feature.rst, .misc.rst files). There's no visible test suite validating that PRs include proper changelog entries with correct format, type categorization, and numbering. This is critical for maintaining release notes quality and preventing incomplete changelog entries from being merged.
- [ ] Create tests/test_changelog_validation.py to validate .rst files in changelogs/ directory
- [ ] Test that changelog entries have valid categories (feature, removal, misc, bugfix, doc, etc.)
- [ ] Test that changelog filenames follow {issue_number}.{type}.rst pattern
- [ ] Test for required content in changelog entries (description, related issue link)
- [ ] Consider adding a pre-commit hook or GitHub workflow to enforce this validation
Create missing integration tests for sanic-ext compatibility in tests/
The dependencies list explicitly includes sanic-ext>=23.12 as a core dependency, but there's no visible test directory shown that validates integration between Sanic core and sanic-ext. Given that sanic-ext is maintained separately but tightly coupled, integration tests would prevent breaking changes and ensure extension functionality works as expected.
- [ ] Analyze existing test structure to understand testing patterns
- [ ] Create tests/test_sanic_ext_integration.py for common sanic-ext features (validators, middleware, OpenAPI)
- [ ] Test that sanic-ext decorators work with core Sanic routing and middleware
- [ ] Add tests validating backward compatibility when sanic-ext versions are updated
- [ ] Document in CONTRIBUTING.md that sanic-ext integration tests must pass
Add missing workflow to validate example code snippets in examples/ directory
The examples/ directory contains many code samples (add_task_sanic.py, authorized_sanic.py, etc.) but there's no visible GitHub workflow to validate these examples run without syntax errors or import failures. Examples are critical for new users and need to work. Currently only coverage.yml and tests.yml workflows exist.
- [ ] Create .github/workflows/validate-examples.yml GitHub Action
- [ ] Add step to run each .py file in examples/ with python -m py_compile
- [ ] Add step to check imports (e.g., using pylint --disable=all --enable=import-error)
- [ ] Configure workflow to run on PRs that modify files in examples/ directory
- [ ] Document in CONTRIBUTING.md that example code must be kept working
🌿Good first issues
- Add type hints to utility functions in sanic/response.py and sanic/request.py — check .coveragerc for coverage gaps and match existing type annotations
- Expand error case documentation in docs/sanic/api/exceptions.rst with concrete code examples for common pitfalls (e.g., handling exceptions in background tasks)
- Create a migration guide from Flask/Django to Sanic in docs/ explaining async/await conversion patterns, middleware translation, and testing strategies for async handlers
⭐Top contributors
Click to expand
- @ahopkins — 55 commits
- @ChihweiLHBird — 6 commits
- @Tronic — 4 commits
- @Peopl3s — 2 commits
- @tkosman — 2 commits
📝Recent commits
Click to expand
785d77f— Prepare for v25.12 release (#3124) (ahopkins)dc0939e— Check state in shutdown for handling uvloop double kill (#3122) (ahopkins)a64dc64— Respect KEEP_ALIVE config (#3121) (ahopkins)7c9b846— Respect LOG_EXTRA in all cases (#3120) (ahopkins)9aef932— Explicit symlink params for static files/dirs (#3117) (ahopkins)41f2b38— Fix static file serving for directories with CJK characters (#3119) (ahopkins)82d8cc4— Return task when creating a task (#3114) (ahopkins)002c8c2— Remove v3.9 and add v3.14 (#3115) (ahopkins)3ae8f8a— Add daemon mode to Sanic CLI (#3110) (ahopkins)8ac6468— Bump dawidd6/action-download-artifact from 3 to 6 in /.github/workflows (#3109) (dependabot[bot])
🔒Security observations
The Sanic framework repository demonstrates a reasonable security posture with established CI/CD pipelines, security policy documentation, and security analysis tooling (bandit). However, there are opportunities for improvement: dependency versions lack upper bounds which could introduce supply chain risks, the security policy lacks detailed in-repo vulnerability disclosure procedures, and configuration files should be audited for accidental secret exposure. The project would benefit from stricter version pinning, enhanced security documentation, and regular security baseline reviews. No critical vulnerabilities were detected in the provided file structure, but deeper code analysis would be required for comprehensive assessment.
- Medium · Outdated Dependency Versions —
Dependencies/Package file content. The dependency specifications in the package file use loose version constraints (sanic>=23.12, sanic-ext>=23.12) without upper bounds. This allows installation of potentially vulnerable future versions without explicit review. The sanic and sanic-ext packages are core framework dependencies and should be carefully pinned or have explicit maximum versions. Fix: Use pinned versions or constrain to specific version ranges (e.g., sanic>=23.12,<24.0) to ensure reproducible builds and reduce exposure to unvetted versions. - Low · Missing Security Policy Documentation —
SECURITY.md. While SECURITY.md exists, it only references an external URL (https://sanic.dev/en/organization/policies.html) without providing in-repo security vulnerability disclosure procedures. This makes it difficult for security researchers to report vulnerabilities directly through the repository. Fix: Expand SECURITY.md with explicit instructions for responsible disclosure, including contact email (security@), PGP key if applicable, and expected response timeline. - Low · Potential Build Configuration Exposure —
docker/Dockerfile, docker/Dockerfile-base, .appveyor.yml, .github/workflows/. Configuration files like docker/Dockerfile, docker/Dockerfile-base, and Makefile are present in the repository. These may contain exposed environment variables, build arguments, or secrets if not properly sanitized. The appveyor.yml and GitHub workflows could also expose secrets if improperly configured. Fix: Audit Dockerfile and CI/CD configurations to ensure no secrets, API keys, or credentials are hardcoded. Use GitHub Secrets for sensitive CI/CD variables. Implement pre-commit hooks to detect secrets. - Low · Bandit Baseline Configuration —
bandit.baseline. The presence of bandit.baseline file suggests security issues have been identified and potentially suppressed. While this is normal for legacy codebases, it indicates known security considerations that may need tracking. Fix: Regularly review and reduce the bandit baseline. Track suppressed issues in a security backlog and work to remediate them. Ensure new code does not bypass security checks.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.