Supabase SQL queries can be run directly from the terminal using the Management API and a curl command, bypassing the web dashboard. The Supabase CLI stores an access token in the macOS Keychain after supabase login. That token, extracted with security find-generic-password and decoded from base64, authenticates curl POST requests to the Management API’s database query endpoint. This approach works reliably on Mac where direct psql connections often fail due to IPv6 routing issues.
If you use Claude Code to build projects, you’ve probably hit a moment where you need to update something in your database. Add a user, change a value, check what’s in a table. The usual move is to open the Supabase dashboard, click into the SQL editor, type your query, and run it.
That works. But there’s a faster way. You can run SQL straight from your terminal with a single curl command, no browser needed. This post covers what Supabase is, how it stores data, and exactly how to query it from the command line.
What is Supabase?
Supabase is an open-source backend platform. It gives you a PostgreSQL database, user authentication, auto-generated APIs, and a web dashboard to manage all of it. Think of it as a self-hostable alternative to Firebase, but built on Postgres instead of a proprietary NoSQL format.
The key difference from Firebase: Supabase uses a real relational database. Your data lives in tables with rows and columns, just like a spreadsheet. You query it with SQL (Structured Query Language), which is the standard language for talking to databases.
A few terms worth knowing:
PostgreSQL (Postgres) is the database engine Supabase runs on. It’s open source, widely used, and extremely capable. When people say “I use Supabase,” they mostly mean “I have a Postgres database hosted by Supabase.”
SQL is how you communicate with that database. SELECT * FROM users means “give me every row from the users table.” INSERT INTO users (email) VALUES ('[email protected]') adds a row. UPDATE users SET approved = true WHERE email = '[email protected]' updates one. If you’ve never written SQL before, these three commands cover probably 80% of what you’ll actually need.
The Supabase dashboard is a web interface at supabase.com where you can browse your tables, run SQL queries, manage auth settings, check logs, and configure your project. For most people, this is how they interact with Supabase.
Two Different APIs (and Why the Distinction Matters)
Supabase exposes two types of APIs, and they’re easy to confuse.
PostgREST is the auto-generated REST API your project gets by default. It lives at your project’s URL (something like https://xyzproject.supabase.co). You use it from your app code to read and write data. It’s filtered through Row Level Security, which means it respects your auth rules.
The Management API lives at api.supabase.com (not your project URL). It’s a separate service for managing Supabase projects programmatically. Creating projects, running migrations, executing raw SQL. This is what platform tools and the Supabase CLI use under the hood. It bypasses Row Level Security, so it’s more powerful and more dangerous.
When you want to run a raw SQL command from the terminal, the Management API is what you want.
Setting Up the Supabase CLI
The Supabase CLI is a command-line tool that lets you manage Supabase projects from your terminal. Install it with Homebrew:
brew install supabase/tap/supabase
Once it’s installed, log in with your Supabase account:
supabase login
This opens a browser window where you authorize the CLI. After you approve it, the CLI stores an access token on your machine. We’ll come back to exactly where that token lives in a minute.
The psql Dead End
Your first instinct might be to connect directly to the database with psql. Supabase provides a connection string in your project settings that looks like:
postgresql://postgres:[password]@db.[project-ref].supabase.co:5432/postgres
This is a direct database connection. It works fine in most environments. But there’s a known issue: Supabase’s database host is IPv6-only, and on a Mac without an IPv6 route configured, the DNS lookup for that hostname either fails or resolves to an address your machine can’t reach.
You’ll see something like “could not translate host name to address” or a timeout. The connection string is technically correct, but the network path isn’t there.
You can sometimes work around this by using the connection pooler URL instead (found under Connection Pooling in your project settings), which routes through an IPv4-compatible proxy. But it’s flakey depending on your setup.
The more reliable path: skip direct database connections entirely and use the Management API over HTTPS.
Where the CLI Stores Your Token
After you run supabase login, the CLI stores your access token in the macOS Keychain. The Keychain is macOS’s built-in credential store. Passwords, tokens, certificates, anything sensitive can be stored there and retrieved securely without writing a plaintext file.
The CLI stores the token under the name “Supabase CLI” in base64 encoding.
Base64 is an encoding scheme that converts binary data (or any string) into a format that only uses letters, numbers, and a few symbols. It’s not encryption, just a way to safely pass data in contexts that might choke on special characters. To use a base64-encoded value, you decode it first.
To extract your Supabase token from the Keychain:
security find-generic-password -s "Supabase CLI" -w | base64 --decode
What this does:
security find-generic-password -s "Supabase CLI" -wfinds the stored password for the service named “Supabase CLI” and prints just the value (-wmeans “print only the password”)| base64 --decodepipes that output through the base64 decoder to get back the original token
The result is a JWT token (a long string starting with eyJ...) that you can use to authenticate with the Management API.
What curl Does
curl is a command-line tool for making HTTP requests. When your browser visits a webpage, it’s making an HTTP GET request. When you submit a form, it’s usually a POST request. curl lets you do the same thing from your terminal, with full control over headers, methods, and request bodies.
You already have curl on your Mac. No installation needed.
Running SQL from the Terminal
Here’s the full command to run a SQL query against your Supabase project:
TOKEN=$(security find-generic-password -s "Supabase CLI" -w | base64 --decode)
PROJECT_REF="your-project-ref-here"
SQL="SELECT * FROM your_table LIMIT 5;"
curl -s -X POST \
"https://api.supabase.com/v1/projects/${PROJECT_REF}/database/query" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d "{\"query\": \"${SQL}\"}"
Replace your-project-ref-here with your project’s reference ID (visible in your Supabase project URL or in Settings > General).
What each part does:
TOKEN=$(...)runs the security command and stores the decoded token in a variablecurl -sruns silently (no progress meter)-X POSTsends an HTTP POST request (required to submit data)- The URL is the Management API endpoint for running database queries
-H "Authorization: Bearer ${TOKEN}"passes your token in the Authorization header, which is how APIs verify who you are-H "Content-Type: application/json"tells the API you’re sending JSON-d "{\"query\": \"${SQL}\"}"is the request body, a JSON object with your SQL query
The response comes back as JSON with your query results.
A Real Example: Approving a User
The reason this workflow came up: we wanted to pre-approve a specific user for access to a project. This came up while building the student progress dashboard. The SQL to do that looks something like:
UPDATE users SET approved = true WHERE email = '[email protected]';
Instead of opening the Supabase dashboard, navigating to the SQL editor, typing the query, and running it, the command is just:
TOKEN=$(security find-generic-password -s "Supabase CLI" -w | base64 --decode)
curl -s -X POST \
"https://api.supabase.com/v1/projects/${PROJECT_REF}/database/query" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"query": "UPDATE users SET approved = true WHERE email = '"'"'[email protected]'"'"';"}'
That’s one command. Claude Code can run it. You can paste it into a skill. You can automate it. The dashboard is good for exploring, but for repeatable operations, the terminal is faster.
Plugging This into Claude Code
Once you’ve verified the pattern works, you can add it to any Claude Code skill or CLAUDE.md file as a reusable step. Something like:
To run SQL against Supabase:
1. Extract token: TOKEN=$(security find-generic-password -s "Supabase CLI" -w | base64 --decode)
2. POST to https://api.supabase.com/v1/projects/PROJECT_REF/database/query
3. Header: Authorization: Bearer $TOKEN
4. Body: {"query": "YOUR SQL HERE"}
Now any session that needs to touch the database can do it automatically, without prompting you to open the dashboard. We updated the c4c-access skill with exactly this pattern so future sessions handle approvals without manual steps.
A Note on Security
The Management API bypasses Row Level Security. That means whatever SQL you run, it runs with full database access. Don’t put this token in a public repo, a shared file, or anywhere it could leak. Storing it in the macOS Keychain (which the CLI does by default) is the right approach. Never hardcode it in a script file.
Further Reading
- Supabase documentation for the full overview of what Supabase can do
- Supabase CLI reference for all available CLI commands
- Management API reference for every endpoint available at api.supabase.com
- Supabase connection pooling for the IPv4-compatible connection option if you want to try psql
- macOS Keychain documentation if you want to understand how the Keychain stores and retrieves credentials
- curl documentation for the full list of flags and options
Common Questions
How do I run Supabase SQL from the terminal?
Extract your token with security find-generic-password -s "Supabase CLI" -w | base64 --decode, then POST your SQL query to https://api.supabase.com/v1/projects/PROJECT_REF/database/query with the token in the Authorization header. The response comes back as JSON.
Why does psql fail to connect to Supabase on Mac?
Supabase’s database host is IPv6-only. If your Mac doesn’t have an IPv6 route configured, DNS lookup fails or times out. The connection pooler URL sometimes works as a workaround, but the Management API over HTTPS is more reliable.
What is the Supabase Management API?
The Management API lives at api.supabase.com and handles project-level operations: running SQL, creating projects, managing migrations. It bypasses Row Level Security, making it more powerful but also requiring careful use. The CLI and platform tools use it internally.
Where does the Supabase CLI store its access token?
On macOS, the token is stored in the Keychain under the service name “Supabase CLI” in base64 encoding. Extract it with security find-generic-password -s "Supabase CLI" -w | base64 --decode. Never hardcode this token in scripts or public repos.
A note from Alex: hi i’m alex - i run code for creatives. i’m a writer so i feel that it is important to say - i had claude write this piece based on my ideas and ramblings, voice notes, and teachings. the concepts were mine but the words themselves aren’t. i want to say that because its important for me to distinguish, as a writer, what is written ‘by me’ and what’s not. maybe that idea will seem insane and antiquated in a year, i’m not sure, but for now it helps me feel okay about putting stuff out there like this that a) i know is helpful and b) is not MY voice but exists within the umbrella of my business and work. If you have any thoughts or musings on this, i’d genuinely love to hear them - its an open question, all of this stuff, and my guess is as good as yours.