Splinter
Supabase Postgres Linter: Performance and Security Advisors
Install / Use
/learn @supabase/SplinterREADME
splinter (Supabase Postgres LINTER)
<img src="docs/assets/splinter-elephant.png" height="250"> <p> <a href=""><img src="https://img.shields.io/badge/postgresql-15+-blue.svg" alt="PostgreSQL version" height="18"></a> <a href="https://github.com/supabase/splinter/blob/master/LICENSE"><img src="https://img.shields.io/pypi/l/markdown-subtemplate.svg" alt="License" height="18"></a> <a href="https://github.com/supabase/splinter/actions"><img src="https://github.com/supabase/splinter/actions/workflows/test.yml/badge.svg" alt="tests" height="18"></a> </p>Documentation: <a href="https://supabase.github.io/splinter" target="_blank">https://supabase.github.io/splinter</a>
Source Code: <a href="https://github.com/supabase/splinter" target="_blank">https://github.com/supabase/splinter</a>
Splinter maintains a set of lints for Supabase projects. It uses SQL queries to identify common database schema issues. Some lints are general purpose for Postgres projects while others are specific to Supabase features storing their data in Postgres e.g. auth and storage.
Usage
If you are only interested in linting a project, a single query containing the latest version of all lints is availble in splinter.sql in the repo root.
Lint Interface
Each lint creates a view that returns a common interface. The interface is:
- name (text) not null -- Name of the lint
- title (text) not null -- Human readable title of the lint
- level (text) not null -- The level of issue. One of ERROR/WARN/INFO
- facing (text) not null -- Is it an internal (to supabase) or an external (user centric) lint. One of INTERNAL/EXTERNAL
- categories (text[]) not null -- Relevant tags for the issue. Any/All of SECURITY/PERFORMANCE (list may grow)
- description (text) not null -- This is a description of the lint and why its an issue
- detail (text) not null -- A text description of the issue that includes references to the specific table/column/constraint/whatever that fails the lint
- remediation (text) optional -- A reference to documentation to describe the issue and how to resolve it
- metadata (jsonb) optional -- Lint specific information, for example referenced entities, or entity types
- cache_key (text) not null -- A short, uniquely identifiable string that users can add to an exclusion list to avoid repeatedly seeing the same lint failures. It should identify the releavnt table/column/constraint. The string should be prefixed with the lint name. For example a lint named "unindexed_foreign_key" might have a unique key "unindexed_foreign_key_public_user_created_by_id"
Deploying to supabase/supabase
To deploy lints to Supabase prod, open a PR against supabase/supabase updating the lint query
If the update includes a new lint, update getHumanReadableTitle and LINT_TYPES.
Contributing a New Lint
To add a new lint using Claude Code, run the /new-lint skill from the .claude/skills/new-lint directory. It will guide you through creating the SQL view, test cases, and documentation.
Development
Supabase PostgreSQL 15+
Setup:
git clone https://github.com/supabase/splinter.git
cd splinter
Building the docs locally
The docs use MkDocs with the Material theme. To install dependencies and serve the site with live reload:
python3 -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
pip install mkdocs-material
mkdocs serve
Then open http://127.0.0.1:8000. Run mkdocs build to output static files to site/.
Tests
All lints tests with a true positive example.
To run the test suite:
docker rmi -f dockerfiles-test && SUPABASE_VERSION=15.1.1.13 docker-compose -f dockerfiles/docker-compose.yml run --rm test
Related Skills
node-connect
353.3kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
111.7kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
353.3kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
353.3kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
