[{"data":1,"prerenderedAt":1161},["ShallowReactive",2],{"blog-en-supabase-backup-github-action":3,"blog-index-en":815},{"id":4,"title":5,"body":6,"category":768,"cover":769,"coverAlt":770,"description":771,"draft":772,"extension":773,"faq":774,"image":792,"keywords":793,"meta":802,"navigation":803,"ogTitle":804,"path":805,"published":806,"seo":807,"stem":808,"tldr":809,"updated":813,"__hash__":814},"blog_en\u002Fblog\u002Fsupabase-backup-github-action.md","Free Supabase backup with a GitHub Action, and the catch",{"type":7,"value":8,"toc":752},"minimark",[9,13,21,24,29,40,49,57,60,64,72,82,85,138,145,152,156,159,176,190,196,199,202,206,215,224,232,241,244,248,251,254,334,337,340,345,348,356,359,363,376,397,403,406,409,415,421,458,464,467,471,474,477,514,517,521,529,547,551,554,570,578,583,591,600,606,609,613,616,644,648,653,696,709,713,744],[10,11,12],"p",{},"Your Supabase project is on the free plan, so nothing is being copied anywhere,\nor it is on Pro and every copy it takes lives inside the account you are worried\nabout losing. In a thread about exactly that, somebody said the answer is a\nSupabase backup GitHub Action: one small file in a repository that dumps your\ndatabase every night and costs nothing.",[10,14,15,16,20],{},"They were right. Supabase publishes the workflow itself, and for a lot of apps\nit is the thing to set up this week. Here is the part those threads leave out:\n",[17,18,19],"strong",{},"it costs no money, and it still has a price."," Every run downloads your whole\ndatabase, and Supabase meters that download.",[10,22,23],{},"Think of it as the data on a phone contract. Your plan comes with a monthly\nallowance, everything your app does draws on it, and a backup is a large\ndownload on the same plan. On the free plan, a nightly copy of a database near\nits size limit uses the whole month's allowance in about ten days. That, and a\nconnection string GitHub cannot reach, are the two things between you and a\nworking backup, and neither is on Supabase's page.",[25,26,28],"h2",{"id":27},"can-you-back-up-supabase-with-a-github-action-for-free","Can you back up Supabase with a GitHub Action for free?",[10,30,31,32,39],{},"Yes, and Supabase documents how. Its page on\n",[33,34,38],"a",{"href":35,"rel":36},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fdeployment\u002Fci\u002Fbackups",[37],"nofollow","automated backups using GitHub Actions","\ngives a workflow that installs the Supabase CLI, dumps your roles, your schema\nand your data into three files, and commits them back into the repository on a\nschedule.",[10,41,42,43,48],{},"GitHub does not charge for it either, within limits. A private repository on\nGitHub Free gets\n",[33,44,47],{"href":45,"rel":46},"https:\u002F\u002Fdocs.github.com\u002Fen\u002Fbilling\u002Fconcepts\u002Fproduct-billing\u002Fgithub-actions",[37],"2,000 Actions minutes a month",",\nand a nightly dump of a small database uses a small part of them.",[10,50,51,52,56],{},"What you get is a copy that leaves Supabase every night and lands on another\ncompany's servers. That is the one thing Supabase's own backups cannot give\nyou, because the daily copies on a paid plan\n",[33,53,55],{"href":54},"\u002Fblog\u002Fdownload-your-supabase-backup","stay inside the account they protect",".",[10,58,59],{},"It is the right answer when three things are true. Your app already lives in a\nGitHub repository, which it does if you switched on GitHub sync in Lovable or\na builder like it. Editing a YAML file does not worry you. And your database is small next to your\nplan's egress allowance. You know the first two already. The third is\narithmetic, and it has its own section below.",[25,61,63],{"id":62},"the-workflow-with-the-schedule-and-the-secret","The workflow, with the schedule and the secret",[10,65,66,67,71],{},"Save this as ",[68,69,70],"code",{},".github\u002Fworkflows\u002Fsupabase-backup.yml"," in a private repository\nthat holds nothing else:",[73,74,80],"pre",{"className":75,"code":77,"language":78,"meta":79},[76],"language-yaml","name: supabase-backup\n\non:\n  schedule:\n    - cron: '17 3 * * *' # every day at 03:17 UTC\n  workflow_dispatch:\n\njobs:\n  backup:\n    runs-on: ubuntu-latest\n    permissions:\n      contents: write\n    env:\n      SUPABASE_DB_URL: ${{ secrets.SUPABASE_DB_URL }}\n    steps:\n      - uses: actions\u002Fcheckout@v7\n      - uses: supabase\u002Fsetup-cli@v3\n        with:\n          version: latest\n      - name: Back up roles\n        run: supabase db dump --db-url \"$SUPABASE_DB_URL\" -f roles.sql --role-only\n      - name: Back up schema\n        run: supabase db dump --db-url \"$SUPABASE_DB_URL\" -f schema.sql\n      - name: Back up data\n        run: >\n          supabase db dump --db-url \"$SUPABASE_DB_URL\" -f data.sql --use-copy --data-only\n          -x \"storage.buckets_vectors\" -x \"storage.vector_indexes\"\n      - uses: stefanzweifel\u002Fgit-auto-commit-action@v7\n        with:\n          commit_message: Supabase backup\n","yaml","",[68,81,77],{"__ignoreMap":79},[10,83,84],{},"It is Supabase's workflow with three changes.",[86,87,88,99,123],"ul",{},[89,90,91,94,95,98],"li",{},[17,92,93],{},"It runs on the schedule and when you press the button, and at no other\ntime."," Supabase's version also runs on every push and every pull request to\n",[68,96,97],{},"main",". Each run is a full download of your database, so in a repository that\nalso holds your app, every change you shipped would spend a backup's worth of\nallowance.",[89,100,101,104,105,110,111,114,115,118,119,122],{},[17,102,103],{},"It runs at 03:17, off the hour."," GitHub says scheduled runs\n",[33,106,109],{"href":107,"rel":108},"https:\u002F\u002Fdocs.github.com\u002Fen\u002Factions\u002Freference\u002Fworkflows-and-actions\u002Fevents-that-trigger-workflows#schedule",[37],"can be delayed at the start of every hour",",\nand that under enough load some queued jobs are dropped. Supabase's example\nuses ",[68,112,113],{},"0 0 * * *",", which is on the hour. Times are UTC unless you add a\n",[68,116,117],{},"timezone",", and any minute other than ",[68,120,121],{},"0"," will do.",[89,124,125,133,134,137],{},[17,126,127,128],{},"The data line matches Supabase's current\n",[33,129,132],{"href":130,"rel":131},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fplatform\u002Fmigrating-within-supabase\u002Fbackup-restore",[37],"backup and restore guide",",\nwhich adds two ",[68,135,136],{},"-x"," exclusions the workflow page does not have. The files you\nkeep are then the ones Supabase's restore instructions are written for.",[10,139,140,141,144],{},"Then the secret. In the repository, open Settings, then Secrets and variables,\nthen Actions, and add a repository secret called ",[68,142,143],{},"SUPABASE_DB_URL",". What goes\ninto it decides whether any of this works, so it gets the next section to\nitself.",[10,146,147,148,151],{},"Once it is saved, run the workflow by hand from the Actions tab, so the first\nrun happens while you are watching. ",[68,149,150],{},"workflow_dispatch"," is the line that gives\nyou the Run workflow button.",[25,153,155],{"id":154},"which-connection-string-goes-in-the-secret","Which connection string goes in the secret?",[10,157,158],{},"The Session pooler string, from the Connect button at the top of your Supabase\nproject. Use it even though Supabase's workflow page shows the direct\nconnection in its example.",[10,160,161,162,165,166,169,170,175],{},"The reason is IPv6, the newer kind of internet address. Supabase's direct\nconnection, the host that begins ",[68,163,164],{},"db."," and ends ",[68,167,168],{},"supabase.co",",\n",[33,171,174],{"href":172,"rel":173},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fplatform\u002Fipv4-address",[37],"uses IPv6 by default",",\nand the same page lists GitHub Actions among the services that only accept\nIPv4. The runner is handed an address it has no route to, and the first dump\nfails before a byte is written. The error says the host name could not be\ntranslated, or that the network is unreachable, often with a long address full\nof colons printed beside it. That address is the IPv6 one. It reads like a\nwrong password or a database that is down, and the real cause is a network the\nrunner is not on.",[10,177,178,179,182,183,186,187,56],{},"Supabase's backup and restore guide says to use the Session pooler string by\ndefault, and the direct one only if your network supports IPv6 or you pay for\nthe IPv4 add-on. You can recognise the pooler string by three things: its user\nname is ",[68,180,181],{},"postgres."," followed by your project's reference, its host ends in\n",[68,184,185],{},"pooler.supabase.com",", and its port is ",[68,188,189],{},"5432",[191,192],"diagram",{"alt":193,"caption":194,"src":195},"A GitHub runner on the left with two routes out of it. The upper route carries the direct host db.[ref].supabase.co, is marked IPv6, and stops at a wall with a cross before the database. The lower route carries the pooler.supabase.com host, is marked IPv4, and reaches the database with a tick.","The runner has no route to the direct connection's IPv6 address. The Session pooler answers on IPv4 and reaches the same database.","\u002Fblog\u002Fsupabase-backup-github-action\u002Fwhich-string-reaches-the-runner-1600x620.png",[10,197,198],{},"The password in it is your database password, the one set when the project was\ncreated, and not an API key. If nobody wrote it down, Supabase lets you reset it\nunder Database Settings; anything else that connects with the old one stops\nworking until you give it the new one.",[10,200,201],{},"That string can read and change every row in your database. It lives in the\nsecret and nowhere else: never in the workflow file, never in a commit message,\nand never pasted into an AI assistant along with the error you were asking\nabout.",[25,203,205],{"id":204},"does-a-supabase-backup-count-against-my-egress","Does a Supabase backup count against my egress?",[10,207,208,209,214],{},"Yes, all of it. Supabase counts as\n",[33,210,213],{"href":211,"rel":212},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fplatform\u002Fmanage-your-usage\u002Fegress",[37],"egress","\nthe data any of its services sends out, and a dump through the pooler is filed\nas Shared Pooler Egress inside the same allowance as your API traffic, your file\ndownloads and everything else your app serves.",[10,216,217,218,223],{},"Back to the phone contract. The allowance resets each billing month, every\nservice your app uses draws on it, and a backup is one more large download. It\nis also a family plan: Supabase applies the quota to\n",[33,219,222],{"href":220,"rel":221},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fplatform\u002Fbilling-on-supabase",[37],"your whole organization",",\nso every project in it draws on the one allowance.",[10,225,226,227,231],{},"On 26 September 2026, Supabase's pricing page gave the free plan 5 GB of egress\na month and a 500 MB limit on each project's database, and the Pro plan 250 GB\nof egress. There is a second 5 GB on the free plan for cached egress, which\ncovers files served from Supabase's CDN, and a backup never touches it. The other free plan limits, and ",[33,228,230],{"href":229},"\u002Fblog\u002Fsupabase-free-plan-limits","what each one does when you cross it",", have an article of their own.",[10,233,234,235,240],{},"Going past the allowance on the free plan does not produce a bill. Supabase\n",[33,236,239],{"href":237,"rel":238},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fplatform\u002Fbilling-faq",[37],"notifies you and gives you a grace period",",\nand if you keep going over, it restricts every project in the organization. It\nsays that can mean API requests answered with a 402 error, a database switched\nto read-only, or projects paused. For an app with customers, that is an outage\nyour backup started.",[10,242,243],{},"This is true of every backup that leaves Supabase, including the one we sell. A\ncopy held outside the account has to be downloaded to get there.",[25,245,247],{"id":246},"how-often-should-the-backup-run","How often should the backup run?",[10,249,250],{},"As often as your allowance pays for, and that comes down to one\nmultiplication: your database size, times the runs in a month.",[10,252,253],{},"Supabase shows your database size on the Database report, under Observability\nin your project. A dump is not exactly that size. It leaves out indexes, which\nare rebuilt from their definitions, and it writes every value out as text. It is\nclose enough to plan with, and it is the number you can look up.",[255,256,257,276],"table",{},[258,259,260],"thead",{},[261,262,263,267,270,273],"tr",{},[264,265,266],"th",{},"Database size",[264,268,269],{},"Daily (30 runs)",[264,271,272],{},"Twice a week",[264,274,275],{},"Weekly",[277,278,279,294,307,321],"tbody",{},[261,280,281,285,288,291],{},[282,283,284],"td",{},"50 MB",[282,286,287],{},"1.5 GB",[282,289,290],{},"0.4 GB",[282,292,293],{},"0.2 GB",[261,295,296,299,302,305],{},[282,297,298],{},"100 MB",[282,300,301],{},"3 GB",[282,303,304],{},"0.9 GB",[282,306,290],{},[261,308,309,312,315,318],{},[282,310,311],{},"250 MB",[282,313,314],{},"7.5 GB",[282,316,317],{},"2.2 GB",[282,319,320],{},"1.1 GB",[261,322,323,326,329,332],{},[282,324,325],{},"500 MB",[282,327,328],{},"15 GB",[282,330,331],{},"4.3 GB",[282,333,317],{},[10,335,336],{},"A month is about 4.3 weeks, which is where the last two columns come from.",[10,338,339],{},"On the free plan, the bottom two daily figures spend more than the whole month's\nallowance before your app has answered a single request. A daily schedule uses\nthe full 5 GB at about 160 MB, and your app's own traffic comes out of the same\nallowance, so read last month's egress on your organization's Usage page before\nyou pick. Weekly fits at every size the free plan allows.",[191,341],{"alt":342,"caption":343,"src":344},"A database with a repeat mark beside two columns of blocks: thirty copies in a month on the left, four on the right. A dashed line marks the monthly allowance. The left column passes it a third of the way up and its blocks above the line are amber. The right column stays well below it, in teal.","A database at the free plan's 500 MB limit, backed up daily and weekly. The dashed line is the free plan's 5 GB of egress for the month.","\u002Fblog\u002Fsupabase-backup-github-action\u002Fthirty-copies-four-copies-1600x680.png",[10,346,347],{},"The cron line is the only thing you change:",[73,349,354],{"className":350,"code":352,"language":353},[351],"language-text","17 3 * * *      every day at 03:17 UTC\n17 3 * * 1,4    Mondays and Thursdays\n17 3 * * 0      Sundays\n","text",[68,355,352],{"__ignoreMap":79},[10,357,358],{},"On Pro the arithmetic mostly stops mattering. 250 GB a month pays for a daily\ndump of one project up to about 8 GB, which is the disk space the Pro plan\nincludes per project.",[25,360,362],{"id":361},"why-does-my-workflow-fail-with-a-pg_dump-version-error","Why does my workflow fail with a pg_dump version error?",[10,364,365,366,369,370,372,373,375],{},"Because the ",[68,367,368],{},"pg_dump"," it ran is older than your database. That only happens to\na workflow that calls ",[68,371,368],{}," directly rather than through the Supabase CLI.\nThe CLI brings its own ",[68,374,368],{},", which is one reason the workflow above uses\nit.",[10,377,378,379,382,383,388,389,391,396],{},"GitHub's ",[68,380,381],{},"ubuntu-latest"," runner comes with\n",[33,384,387],{"href":385,"rel":386},"https:\u002F\u002Fgithub.com\u002Factions\u002Frunner-images\u002Fblob\u002Fmain\u002Fimages\u002Fubuntu\u002FUbuntu2404-Readme.md",[37],"PostgreSQL 16 installed",".\nSupabase projects can run Postgres 17, and Postgres documents that ",[68,390,368],{},[33,392,395],{"href":393,"rel":394},"https:\u002F\u002Fwww.postgresql.org\u002Fdocs\u002Fcurrent\u002Fapp-pgdump.html",[37],"will not dump from a server newer than its own major version",",\nrefusing rather than risking a bad file. The run stops with:",[73,398,401],{"className":399,"code":400,"language":353},[351],"pg_dump: error: aborting because of server version mismatch\npg_dump: detail: server version: 17.…; pg_dump version: 16.…\n",[68,402,400],{"__ignoreMap":79},[10,404,405],{},"Your project's version is under Project Settings, then General, if you want to\nconfirm it. Nothing about your credentials is wrong.",[10,407,408],{},"The fix is two steps. Add PostgreSQL's own package repository so the runner can\ninstall the version 17 client, then call that client by its full path:",[73,410,413],{"className":411,"code":412,"language":78,"meta":79},[76],"- name: Install the Postgres 17 client\n  run: |\n    sudo apt-get install -y postgresql-common\n    sudo \u002Fusr\u002Fshare\u002Fpostgresql-common\u002Fpgdg\u002Fapt.postgresql.org.sh -y\n    sudo apt-get install -y postgresql-client-17\n- name: Back up\n  run: \u002Fusr\u002Flib\u002Fpostgresql\u002F17\u002Fbin\u002Fpg_dump \"$SUPABASE_DB_URL\" …\n",[68,414,412],{"__ignoreMap":79},[10,416,417,418,420],{},"Keep the arguments you already had after the connection string. The full path\nmatters: on Ubuntu, plain ",[68,419,368],{}," is a wrapper that picks a version for you,\nand the runner already has a PostgreSQL 16 installation for it to pick.",[10,422,423,424,426,427,430,431,439,440,443,444,447,448,450,451,454,455,457],{},"The CLI's own ",[68,425,368],{}," has a version as well, and it is not read from your\nproject. With no ",[68,428,429],{},"supabase\u002Fconfig.toml"," beside the workflow, which is the case\nin a repository that holds nothing else, the CLI\n",[33,432,435,436,438],{"href":433,"rel":434},"https:\u002F\u002Fgithub.com\u002Fsupabase\u002Fcli\u002Fblob\u002F66ccc6f63a9a26b29c368698994a0843d23b80be\u002Fapps\u002Fcli\u002Fsrc\u002Fcommand-internal\u002Fdb-config.toml-read.ts#L176",[37],"picks ",[68,437,368],{}," 17",".\nOn a project still running Postgres 15, the ",[68,441,442],{},"data.sql"," it writes then carries\n",[68,445,446],{},"SET transaction_timeout = 0",", a setting Postgres 15 does not have, and the\nreplay stops on that line in any Postgres 15 database, the project the file came\nfrom included. We reproduced it on 4 October 2026 with ",[68,449,368],{}," 17.11 and\nPostgres 15.19. If your project is on 15, add one line to the job's ",[68,452,453],{},"env"," block\nso the CLI runs the matching ",[68,456,368],{},":",[73,459,462],{"className":460,"code":461,"language":78,"meta":79},[76],"env:\n  SUPABASE_DB_URL: ${{ secrets.SUPABASE_DB_URL }}\n  SUPABASE_DB_MAJOR_VERSION: '15'\n",[68,463,461],{"__ignoreMap":79},[10,465,466],{},"The backup itself runs without an error either way, so without that line the\nmismatch only shows on the day the file is replayed.",[25,468,470],{"id":469},"can-i-commit-the-backup-to-my-repository","Can I commit the backup to my repository?",[10,472,473],{},"To a private one, yes. That is what Supabase's workflow does, and its page says\ntwice that you should never back up your data to a public repository.",[10,475,476],{},"Three things about a repository as a home for a database, none of them on that\npage:",[86,478,479,493,499],{},[89,480,481,484,485,487,488,492],{},[17,482,483],{},"Everyone who can read the repository can read your users."," ",[68,486,442],{},"\nholds every row: email addresses, names, whatever your tables keep, and\n",[33,489,491],{"href":490},"\u002Fblog\u002Fsupabase-backup-auth-users","your accounts as well",". That is why the\nworkflow gets a repository of its own with nobody else on it, rather than the\none your app's code lives in, which your builder may sync and a freelancer may\none day be invited to.",[89,494,495,498],{},[17,496,497],{},"Every night's copy stays in the history."," Git keeps every version of every\nfile. When a customer asks you to delete their account, their row is still in\nevery earlier commit of that repository until you rewrite its history.",[89,500,501,504,505,510,511,513],{},[17,502,503],{},"It stops working at 100 MiB."," GitHub warns about files over 50 MiB and\n",[33,506,509],{"href":507,"rel":508},"https:\u002F\u002Fdocs.github.com\u002Fen\u002Frepositories\u002Fworking-with-files\u002Fmanaging-large-files\u002Fabout-large-files-on-github",[37],"blocks files over 100 MiB",",\nand the same page says Git is not designed to handle large SQL files. The\nnight ",[68,512,442],{}," crosses that line, the commit step fails, and every run after\nit fails the same way.",[10,515,516],{},"As you get close, the same workflow can upload the three files to a storage\nbucket you own instead of committing them. Or it is the point where doing this\nyourself has stopped being cheap, which is where the last section starts.",[25,518,520],{"id":519},"what-does-the-workflow-not-copy","What does the workflow not copy?",[10,522,523,524,528],{},"Your uploaded files. Supabase Storage keeps each file outside the database and\na row describing it inside, so the dump carries the row and not the picture.\n",[33,525,527],{"href":526},"\u002Fblog\u002Fsupabase-storage-backup","Backing up Storage"," is a job of its own, on\nevery route there is.",[10,530,531,532,535,536,538,539,542,543,546],{},"Your users are in it. The data dump walks the ",[68,533,534],{},"auth"," schema where your accounts\nlive, and searching ",[68,537,442],{}," for ",[68,540,541],{},"auth.users"," shows them. The project around\nthe database is not: Edge Functions, auth provider settings, API keys and\nsecrets are configuration rather than data, and\n",[33,544,545],{"href":54},"the list of what neither copy holds"," is\nthe one to read before you need it.",[25,548,550],{"id":549},"does-a-green-run-mean-the-backup-worked","Does a green run mean the backup worked?",[10,552,553],{},"It means the job finished without an error, which is a smaller claim. Three\nquite different results end in the same green tick:",[555,556,557,560,563],"ol",{},[89,558,559],{},"A good dump of the right project.",[89,561,562],{},"A dump of the wrong project, because the secret holds the string for a\nstaging copy.",[89,564,565,566,569],{},"A dump with no rows in it, because somebody edited the data line and\n",[68,567,568],{},"--data-only"," went missing, which turns it back into the schema dump.",[10,571,572,573,577],{},"One result leaves no mark at all. A scheduled run GitHub drops under load does\nnot show up as a failure, because there is no run to fail. And when a run does\nfail, GitHub sends the notice to\n",[33,574,576],{"href":107,"rel":575},[37],"the person who last edited the cron line",".\nIf a freelancer set this up for you, the email about your backup goes to them.",[191,579],{"alt":580,"caption":581,"src":582},"A finished job marked with a green tick. One line leaves it and forks into two identical file panels. The upper file's rows are all filled. The lower file's rows stop after two and the rest are empty dashed outlines.","Both files came out of a run that finished without an error. Nothing in the run tells you which one you have.","\u002Fblog\u002Fsupabase-backup-github-action\u002Fgreen-run-short-file-1600x740.png",[10,584,585,586,590],{},"A restore is the only thing that tells them apart. Replay the three files into a\nthrowaway Supabase project or a local one, compare the row counts of the tables\nyou care about with the live ones, and sign in as a real user.\n",[33,587,589],{"href":588},"\u002Fblog\u002Fhow-to-restore-a-supabase-backup","How to restore a Supabase backup"," has\nthe commands, in the order Supabase gives them. Do it once now, and again every\ntime you change the workflow.",[10,592,593,594,599],{},"You can also have every run do the restore and the counting for you. We\npublished a version of this workflow as an open-source GitHub Action,\n",[33,595,598],{"href":596,"rel":597},"https:\u002F\u002Fgithub.com\u002FReeve-page\u002Fsupabase-backup-action",[37],"Reeve-page\u002Fsupabase-backup-action",".\nIt takes the same three dumps, keeps the copy as a workflow artifact or\nin an S3 or R2 bucket, then replays it into a throwaway Supabase database on the\nrunner and compares the row count of every table with the file. The run goes\ngreen only when every table came back with the rows the file holds:",[73,601,604],{"className":602,"code":603,"language":78,"meta":79},[76],"- uses: Reeve-page\u002Fsupabase-backup-action@v1\n  with:\n    db-url: ${{ secrets.SUPABASE_DB_URL }}\n",[68,605,603],{"__ignoreMap":79},[10,607,608],{},"It is free and MIT-licensed. Every run still downloads the whole database, so\nthe egress arithmetic above applies to it unchanged, and the sign-in is still\nyours to test.",[25,610,612],{"id":611},"when-should-i-stop-doing-this-myself","When should I stop doing this myself?",[10,614,615],{},"When the arithmetic stops working, when the file outgrows the repository, or\nwhen nobody is restoring the copies. Any one of them is enough.",[86,617,618,624,632,638],{},[89,619,620,623],{},[17,621,622],{},"Your database has outgrown the free allowance."," Pro raises egress to 250 GB\nand adds Supabase's own daily backups, kept for seven days, which restore with\na button. Keep the workflow running beside them, because those copies live\ninside the account.",[89,625,626,631],{},[17,627,628,630],{},[68,629,442],{}," is heading for 100 MiB."," Moving it to a bucket is more YAML, and\nmore for somebody to keep working.",[89,633,634,637],{},[17,635,636],{},"Nobody has restored a copy."," The workflow will go on writing files whether\nor not they open.",[89,639,640,643],{},[17,641,642],{},"Your users upload things."," The workflow does not reach them, and the job\nthat does is a second one to keep alive.",[25,645,647],{"id":646},"where-reeve-care-fits","Where Reeve Care fits",[10,649,650],{},[17,651,652],{},"Care takes the copy on a schedule, keeps it outside your Supabase account,\nand checks every copy before it counts.",[86,654,655,661,667,673,679],{},[89,656,657,660],{},[17,658,659],{},"Daily on Care, and more often on the plans above it",", with nothing in your\nrepository and no connection string sitting in CI.",[89,662,663,666],{},[17,664,665],{},"Read back and counted."," Every copy is opened and counted against what\nwent in, and the date on your dashboard is the last copy that passed that\ncheck, never the last run.",[89,668,669,672],{},[17,670,671],{},"Your accounts are in it",", and your uploaded files come too once you\nconnect a Storage credential.",[89,674,675,678],{},[17,676,677],{},"Restoring is a button",", and a copy of the current state is taken before\nanything is replaced.",[89,680,681,684,685,688,689,691,692,695],{},[17,682,683],{},"Any copy downloads as a zip"," holding ",[68,686,687],{},"schema.sql",", ",[68,690,442],{}," and\n",[68,693,694],{},"roles.sql",", the same three files this workflow makes, plus a count of the\nrows in every table.",[10,697,698,699,703,704,708],{},"Care keeps a copy of your Supabase database. The copy, the check and the\nrestore are drawn step by step on the ",[33,700,702],{"href":701},"\u002Fsupabase-backups","Supabase backups page",",\nand ",[33,705,707],{"href":706},"\u002Fpricing","what each plan includes"," is on the pricing page.",[25,710,712],{"id":711},"what-to-do-this-week","What to do this week",[714,715,716],"key-takeaways",{},[86,717,718,721,727,730,738,741],{},[89,719,720],{},"Look up your database size and last month's egress, and pick the schedule from the table before you write the cron line.",[89,722,723,724,726],{},"Create a private repository that holds nothing but the workflow, and put the Session pooler string in its ",[68,725,143],{}," secret.",[89,728,729],{},"If you started from Supabase's example, delete the push and pull request triggers and move the cron off the hour.",[89,731,732,733,538,735,737],{},"Run it once by hand from the Actions tab, then search ",[68,734,442],{},[68,736,541],{}," and for a table you know has rows.",[89,739,740],{},"Restore one copy into a throwaway project and sign in as a real user.",[89,742,743],{},"Copy your Storage files on a job of their own.",[10,745,746,747,751],{},"Before you close this tab, open your organization's Usage page in Supabase and\nread last month's egress. That figure, next to your database size, picks your\ncron line. And if you are still weighing the free route against the paid ones,\n",[33,748,750],{"href":749},"\u002Fblog\u002Fsupabase-backup-tools-compared","the four kinds of Supabase backup tool","\nare compared side by side.",{"title":79,"searchDepth":753,"depth":753,"links":754},3,[755,757,758,759,760,761,762,763,764,765,766,767],{"id":27,"depth":756,"text":28},2,{"id":62,"depth":756,"text":63},{"id":154,"depth":756,"text":155},{"id":204,"depth":756,"text":205},{"id":246,"depth":756,"text":247},{"id":361,"depth":756,"text":362},{"id":469,"depth":756,"text":470},{"id":519,"depth":756,"text":520},{"id":549,"depth":756,"text":550},{"id":611,"depth":756,"text":612},{"id":646,"depth":756,"text":647},{"id":711,"depth":756,"text":712},"Backups","\u002Fblog\u002Fsupabase-backup-github-action\u002Fcover-1200x630.png","A database inside a Supabase enclosure, a pipe leading out through a meter whose needle rests in the amber band, and nightly files.","A Supabase backup GitHub Action costs nothing and suits a lot of apps. The workflow, the connection string that works on GitHub, and the egress each run uses.",false,"md",[775,778,781,783,786,789],{"q":776,"a":777},"Can I back up Supabase for free?","Yes. Supabase documents a GitHub Actions workflow that installs its CLI, dumps your roles, schema and data into three files on a schedule, and commits them to the repository. A private repository on GitHub Free gets 2,000 Actions minutes a month, and a nightly dump of a small database uses a small part of them. What the backup does spend is your Supabase egress allowance, because every run downloads the whole database.",{"q":779,"a":780},"How often should a Supabase backup cron run?","As often as your egress allowance can pay for. Multiply your database size by the runs in a month: a 100 MB database dumped daily moves about 3 GB, and a 500 MB one about 15 GB. The free plan includes 5 GB for the whole organization, shared with your app's own traffic. Put the job on a minute that is not on the hour, because GitHub says scheduled runs at the start of an hour can be delayed, and some dropped.",{"q":205,"a":782},"Yes. Supabase counts as egress the data any of its services sends out, and a dump through the connection pooler is filed as Shared Pooler Egress inside the same allowance as your API traffic. The allowance belongs to the whole organization, not to one project. On the free plan, going over it repeatedly ends in restrictions on every project in the organization.",{"q":784,"a":785},"Why does my backup workflow fail on the first run?","Two failures belong to this setup. The first is the connection string: Supabase's direct connection uses IPv6 unless you pay for the IPv4 add-on, and Supabase lists GitHub Actions among the services that reach only IPv4, so use the Session pooler string. The second hits workflows that call pg_dump directly: the runner's PostgreSQL 16 client refuses to dump a Postgres 17 project and stops with aborting because of server version mismatch.",{"q":787,"a":788},"Can I commit my Supabase backup to my GitHub repository?","To a private one, yes, which is what Supabase's workflow does. Never to a public one, and Supabase says so twice on the same page. Keep it in a repository of its own that nobody else can read, because the data file holds your users' email addresses. Expect to move it as the database grows: GitHub warns about files over 50 MiB and refuses files over 100 MiB.",{"q":790,"a":791},"How do I know the backup file is any good?","Restore it. A green run means the job finished without an error, and a dump of the wrong project or a dump with no rows in it finish the same way. Replay the three files into a throwaway Supabase project or a local one, compare the row counts of the tables you care about, and sign in as a real user. That is the check that tells you whether the file opens.","\u002Fblog\u002Fsupabase-backup-github-action\u002Fcard-800x500.png",[794,795,796,797,798,799,800,801],"supabase backup github action","automate supabase backup","supabase backup cron","free supabase backup automation","supabase pg_dump github actions","scheduled supabase backup","supabase backup workflow","backup supabase free tier automatically",{},true,"Free Supabase backup with a GitHub Action","\u002Fblog\u002Fsupabase-backup-github-action","2026-09-27",{"title":5,"description":771},"blog\u002Fsupabase-backup-github-action",[810,811,812],"A Supabase backup GitHub Action runs the Supabase CLI on a schedule and commits the dump to a private repository. It costs nothing, and for a lot of apps it is the right answer.","Every run downloads your whole database, and Supabase counts that as egress. The free plan includes 5 GB a month for the whole organization, and a daily dump of a database near the 500 MB limit uses about three times that.","Supabase's own example connects with a string GitHub's runners cannot reach. Put the Session pooler string in the secret, and restore one copy before you trust the rest.","2026-10-05","lhE5cbYSwBQ7Y4ovFWUD4z6y8wIg9Mu1UHonqJODC1U",[816,823,829,835,841,847,852,858,864,870,876,882,887,893,894,899,904,910,916,921,927,933,939,945,951,957,963,969,974,980,986,992,998,1004,1010,1016,1022,1028,1034,1040,1046,1051,1057,1063,1069,1075,1081,1087,1093,1098,1104,1110,1116,1122,1127,1133,1139,1145,1150,1156],{"path":817,"title":818,"description":819,"published":820,"category":821,"image":822,"draft":772},"\u002Fblog\u002Fbase44-security-scan","Base44 security scan: the one thing only it can see","The Base44 security scan checks seven kinds of problem from inside your app. Here is the half it reads that nothing outside can, and the half it never looks at.","2026-10-10","Security basics","\u002Fblog\u002Fbase44-security-scan\u002Fcard-800x500.png",{"path":824,"title":825,"description":826,"published":827,"category":821,"image":828,"draft":772},"\u002Fblog\u002Fapi-key-leaked-what-to-do","Your API key leaked. Here is the order to do things in","An API key leaked and you want to know what to do first. Not every key in your frontend is one, and the order matters more than the speed.","2026-10-09","\u002Fblog\u002Fapi-key-leaked-what-to-do\u002Fcard-800x500.png",{"path":830,"title":831,"description":832,"published":833,"category":821,"image":834,"draft":772},"\u002Fblog\u002Finfinite-recursion-in-policy-for-relation","\"Infinite recursion detected in policy\" without disabling RLS","\"Infinite recursion detected in policy for relation\" means your Supabase policy asked the table it protects. Here is how to break the circle.","2026-10-08","\u002Fblog\u002Finfinite-recursion-in-policy-for-relation\u002Fcard-800x500.png",{"path":836,"title":837,"description":838,"published":839,"category":821,"image":840,"draft":772},"\u002Fblog\u002Fno-api-key-found-in-request","\"No API key found in request\" in Supabase, and the wrong fix","\"No API key found in request\" means your Supabase request arrived without a key. Most answers you find point at your database rules instead.","2026-10-07","\u002Fblog\u002Fno-api-key-found-in-request\u002Fcard-800x500.png",{"path":842,"title":843,"description":844,"published":845,"category":821,"image":846,"draft":772},"\u002Fblog\u002Fis-base44-safe","Is Base44 safe? What 5,442 live Base44 apps showed","Is Base44 safe? We ran nine checks on 5,442 live Base44 apps. Almost all scored B for reasons the owner never chose, and one question nobody can answer.","2026-10-06","\u002Fblog\u002Fis-base44-safe\u002Fcard-800x500.png",{"path":848,"title":849,"description":850,"published":813,"category":821,"image":851,"draft":772},"\u002Fblog\u002Fmove-a-secret-to-an-edge-function","Hide an API key: move it to a Supabase Edge Function","Hiding an API key means moving it off the browser, and a Supabase Edge Function is the smallest place to put it. Two steps around the move matter more.","\u002Fblog\u002Fmove-a-secret-to-an-edge-function\u002Fcard-800x500.png",{"path":853,"title":854,"description":855,"published":856,"category":821,"image":857,"draft":772},"\u002Fblog\u002Fenv-file-exposed-on-your-server","Is your .env file exposed? The twelve paths to check","Is your .env file exposed on your own web server? Twelve addresses tell you in a minute, and a hit means everything in the file is already public.","2026-10-04","\u002Fblog\u002Fenv-file-exposed-on-your-server\u002Fcard-800x500.png",{"path":859,"title":860,"description":861,"published":862,"category":821,"image":863,"draft":772},"\u002Fblog\u002Fis-v0-safe","v0 security: all 1,790 v0 apps we scanned got an A","v0 security, measured on 1,790 live v0 apps: every one graded A. Only 17 named a database, and that is most of what the A is measuring.","2026-10-03","\u002Fblog\u002Fis-v0-safe\u002Fcard-800x500.png",{"path":865,"title":866,"description":867,"published":868,"category":821,"image":869,"draft":772},"\u002Fblog\u002Fis-bolt-safe","Is Bolt safe? What 1,123 live Bolt apps showed","Is Bolt safe? We ran nine checks on 1,123 live Bolt apps. The hosting came back clean. The findings were API keys and open tables inside the apps.","2026-10-02","\u002Fblog\u002Fis-bolt-safe\u002Fcard-800x500.png",{"path":871,"title":872,"description":873,"published":874,"category":821,"image":875,"draft":772},"\u002Fblog\u002Fis-supabase-down-or-your-app","Is Supabase down, or is it your app? How to tell","Is Supabase down, or is it your app? A paused project, a full database and a bug of your own all look like an outage. Four checks tell them apart.","2026-10-01","\u002Fblog\u002Fis-supabase-down-or-your-app\u002Fcard-800x500.png",{"path":877,"title":878,"description":879,"published":880,"category":821,"image":881,"draft":772},"\u002Fblog\u002Fdoes-supabase-encrypt-my-data","Does Supabase encrypt my data? Yes. Here is what it stops","Does Supabase encrypt data? Yes: AES-256 at rest, TLS in transit, SOC 2 and ISO 27001 audited. What each one covers, and the leak none of them stops.","2026-09-30","\u002Fblog\u002Fdoes-supabase-encrypt-my-data\u002Fcard-800x500.png",{"path":229,"title":883,"description":884,"published":885,"category":821,"image":886,"draft":772},"Supabase free plan limits, and what happens at each one","The Supabase free plan limits you to 500 MB of database and 5 GB of egress, with no backups. What happens as you cross each line, and what $25 changes.","2026-09-29","\u002Fblog\u002Fsupabase-free-plan-limits\u002Fcard-800x500.png",{"path":888,"title":889,"description":890,"published":891,"category":768,"image":892,"draft":772},"\u002Fblog\u002Ftest-your-supabase-backup","Test your Supabase backup before the day you need it","How to test your Supabase backup: restore it into a spare project, compare the row counts, sign in, and check for the line a cut-off file is missing.","2026-09-28","\u002Fblog\u002Ftest-your-supabase-backup\u002Fcard-800x500.png",{"path":805,"title":5,"description":771,"published":806,"category":768,"image":792,"draft":772},{"path":54,"title":895,"description":896,"published":897,"category":768,"image":898,"draft":772},"Why you can't download your Supabase backup","You can't download your Supabase backup on a current project, because the daily copy is a physical snapshot. How to tell, and how to hold a copy of your own.","2026-09-26","\u002Fblog\u002Fdownload-your-supabase-backup\u002Fcard-800x500.png",{"path":900,"title":901,"description":902,"published":897,"category":821,"image":903,"draft":772},"\u002Fblog\u002Fsupabase-permission-denied-for-table","Supabase \"permission denied for table\": the missing grant","From October 30, a new Supabase table answers \"permission denied for table\" until you grant access. The grant the email shows is half the fix.","\u002Fblog\u002Fsupabase-permission-denied-for-table\u002Fcard-800x500.png",{"path":905,"title":906,"description":907,"published":908,"category":821,"image":909,"draft":772},"\u002Fblog\u002Fopen-api-endpoint-exposed","Is an open API endpoint a security problem? Look at the JSON","Your scan flagged an open API endpoint. Whether it matters depends on what came back, and most of the ones we found were the platform's own.","2026-09-25","\u002Fblog\u002Fopen-api-endpoint-exposed\u002Fcard-800x500.png",{"path":911,"title":912,"description":913,"published":914,"category":821,"image":915,"draft":772},"\u002Fblog\u002Flovable-security-scan","Lovable security scan: the one thing it cannot prove","Lovable security scan: what the Quick and Deep scans check, when each one runs, and the one thing no scan from inside your project can prove.","2026-09-24","\u002Fblog\u002Flovable-security-scan\u002Fcard-800x500.png",{"path":490,"title":917,"description":918,"published":919,"category":768,"image":920,"draft":772},"Why your Supabase dump has no users in it","Run supabase db dump on its own and you get the shape of your database and none of its rows, with the auth schema your users live in left out entirely.","2026-09-23","\u002Fblog\u002Fsupabase-backup-auth-users\u002Fcard-800x500.png",{"path":922,"title":923,"description":924,"published":925,"category":821,"image":926,"draft":772},"\u002Fblog\u002Fdomain-and-certificate-expiry","Domain expired, website down: what actually happens next","Your domain expired and your website is down. Here is the clock you are on, why a lapsed certificate is the easier of the two, and how to check both.","2026-09-22","\u002Fblog\u002Fdomain-and-certificate-expiry\u002Fcard-800x500.png",{"path":928,"title":929,"description":930,"published":931,"category":821,"image":932,"draft":772},"\u002Fblog\u002Fis-lovable-safe","Is Lovable safe? What 18,554 live Lovable apps showed","Is Lovable safe? We ran nine checks on 18,554 live Lovable apps. The platform was the cleanest of five builders. Every finding was inside the app itself.","2026-09-21","\u002Fblog\u002Fis-lovable-safe\u002Fcard-800x500.png",{"path":934,"title":935,"description":936,"published":937,"category":821,"image":938,"draft":772},"\u002Fblog\u002Fvibe-coded-app-security-checklist","The vibe coding security checklist, in nine checks","A vibe coding security checklist with nine items, each one something anyone can verify about your live app from outside, and each with a one-line test.","2026-09-20","\u002Fblog\u002Fvibe-coded-app-security-checklist\u002Fcard-800x500.png",{"path":940,"title":941,"description":942,"published":943,"category":821,"image":944,"draft":772},"\u002Fblog\u002Fstripe-secret-key-in-frontend","A Stripe secret key exposed in your frontend can move money","A Stripe secret key exposed in your frontend can refund, charge and read every customer record you hold. Your pk_live_ key is meant to be there.","2026-09-19","\u002Fblog\u002Fstripe-secret-key-in-frontend\u002Fcard-800x500.png",{"path":946,"title":947,"description":948,"published":949,"category":821,"image":950,"draft":772},"\u002Fblog\u002Fvite-and-next-public-env-vars","Vite env variables exposed: VITE_ and NEXT_PUBLIC_ mean publish this","Vite env variables exposed in your app did what the prefix asked. VITE_ and NEXT_PUBLIC_ mean publish this, and the AI that added one never knew the cost.","2026-09-18","\u002Fblog\u002Fvite-and-next-public-env-vars\u002Fcard-800x500.png",{"path":952,"title":953,"description":954,"published":955,"category":821,"image":956,"draft":772},"\u002Fblog\u002Fbase44-source-maps","Base44 security: what a scan flags, and what is yours to fix","Base44 security on 5,438 scanned apps: three findings on nearly every one are the platform's, the source map is Base44's badge, and what is yours is short.","2026-09-17","\u002Fblog\u002Fbase44-source-maps\u002Fcard-800x500.png",{"path":958,"title":959,"description":960,"published":961,"category":821,"image":962,"draft":772},"\u002Fblog\u002Fis-cursor-ai-safe","Is Cursor AI safe? The editor, the code, and the app you shipped","Is Cursor AI safe? Three questions in one search: what Cursor keeps, what the code it writes gets wrong, and whether the app you shipped is open.","2026-09-16","\u002Fblog\u002Fis-cursor-ai-safe\u002Fcard-800x500.png",{"path":964,"title":965,"description":966,"published":967,"category":821,"image":968,"draft":772},"\u002Fblog\u002Fis-replit-safe","Is Replit safe? What we found in 3,042 live Replit apps","Is Replit safe? We ran nine external checks on 3,042 live Replit apps. The host was not where the findings were. The app each owner published was.","2026-09-15","\u002Fblog\u002Fis-replit-safe\u002Fcard-800x500.png",{"path":526,"title":970,"description":971,"published":972,"category":768,"image":973,"draft":772},"Supabase storage backup: why your database copy has no files","A Supabase storage backup is a separate job. Database backups keep the list of your files and none of the files, so a restore leaves every upload broken.","2026-09-14","\u002Fblog\u002Fsupabase-storage-backup\u002Fcard-800x500.png",{"path":975,"title":976,"description":977,"published":978,"category":768,"image":979,"draft":772},"\u002Fblog\u002Fsupabase-point-in-time-recovery","Supabase point-in-time recovery: what it costs, what it misses","Supabase point-in-time recovery rewinds your database to any second in the last week. It costs $100 a month on top of Pro, and it covers your database only.","2026-09-13","\u002Fblog\u002Fsupabase-point-in-time-recovery\u002Fcard-800x500.png",{"path":981,"title":982,"description":983,"published":984,"category":768,"image":985,"draft":772},"\u002Fblog\u002Fsupabase-project-paused-recover","Supabase project paused? Your data is still there","Supabase paused your project after a week of inactivity. Nothing is deleted, Restore sits beside the project name, and you have a year before that changes.","2026-09-12","\u002Fblog\u002Fsupabase-project-paused-recover\u002Fcard-800x500.png",{"path":987,"title":988,"description":989,"published":990,"category":821,"image":991,"draft":772},"\u002Fblog\u002Fsafest-ai-app-builder","Which AI app builder is safest? We scanned 30,998 apps","Which AI app builder is safest? We scanned 30,998 live apps from Lovable, Base44, Replit, v0 and Bolt. The builder is not what decides your grade.","2026-09-11","\u002Fblog\u002Fsafest-ai-app-builder\u002Fcard-800x500.png",{"path":993,"title":994,"description":995,"published":996,"category":821,"image":997,"draft":772},"\u002Fblog\u002Fenable-rls-on-every-supabase-table","Enable Row Level Security on every Supabase table, then prove it","Enabling Row Level Security in Supabase with no policy locks a table completely. A policy without the setting does nothing. Here is the SQL, and the test.","2026-09-10","\u002Fblog\u002Fenable-rls-on-every-supabase-table\u002Fcard-800x500.png",{"path":999,"title":1000,"description":1001,"published":1002,"category":821,"image":1003,"draft":772},"\u002Fblog\u002Fsupabase-rls-disabled-in-public","Supabase \"RLS disabled in public\": what the warning misses","Supabase reports \"RLS disabled in public\" as an error. It says nothing about the read policy that leaves your table just as open to strangers.","2026-09-09","\u002Fblog\u002Fsupabase-rls-disabled-in-public\u002Fcard-800x500.png",{"path":1005,"title":1006,"description":1007,"published":1008,"category":821,"image":1009,"draft":772},"\u002Fblog\u002Frotate-supabase-service-role-key","How to rotate a leaked Supabase service_role key","Supabase says fix the leak first. Other guides say rotate now. Which is right depends on where your service_role key leaked.","2026-09-08","\u002Fblog\u002Frotate-supabase-service-role-key\u002Fcard-800x500.png",{"path":1011,"title":1012,"description":1013,"published":1014,"category":821,"image":1015,"draft":772},"\u002Fblog\u002Fvibe-coding-security-scanners-compared","Vibe coding security scanners compared, including ours","The best vibe coding security scanner comes down to three questions no feature list answers. Ten tools compared, with prices, and the jobs Reeve does not do.","2026-09-07","\u002Fblog\u002Fvibe-coding-security-scanners-compared\u002Fcard-800x500.png",{"path":1017,"title":1018,"description":1019,"published":1020,"category":821,"image":1021,"draft":772},"\u002Fblog\u002Fsupabase-security-checker","Supabase security checker: run the five checks yourself","A Supabase security checker reads your published app instead of your project settings. Here are the five checks it runs, and how to run each one yourself.","2026-09-06","\u002Fblog\u002Fsupabase-security-checker\u002Fcard-800x500.png",{"path":1023,"title":1024,"description":1025,"published":1026,"category":821,"image":1027,"draft":772},"\u002Fblog\u002Fvibe-coding-security-scanner","Vibe coding security scanner: what a URL scan misses","A vibe coding security scanner reads your live app from outside. Here is what that covers, the four things it cannot see, and how to read the result.","2026-09-05","\u002Fblog\u002Fvibe-coding-security-scanner\u002Fcard-800x500.png",{"path":1029,"title":1030,"description":1031,"published":1032,"category":821,"image":1033,"draft":772},"\u002Fblog\u002Fmissing-security-headers","Missing security headers: when it actually matters","Missing security headers is the finding our scanner prints most. Here is what it protects against, and when it is the least urgent line on your report.","2026-09-04","\u002Fblog\u002Fmissing-security-headers\u002Fcard-800x500.png",{"path":1035,"title":1036,"description":1037,"published":1038,"category":821,"image":1039,"draft":772},"\u002Fblog\u002Fopenai-api-key-exposed-in-frontend","Your OpenAI API key is exposed in your frontend. Rotate it.","An OpenAI API key exposed in your frontend cannot be locked to a domain. Rotate it today, move the call behind your own endpoint, and cap the spend.","2026-09-03","\u002Fblog\u002Fopenai-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":1041,"title":1042,"description":1043,"published":1044,"category":821,"image":1045,"draft":772},"\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps","An API key exposed in your frontend: what 30,998 apps shipped","An API key exposed in your frontend is usually a Google Maps key. We scanned 30,998 live vibe-coded apps and counted which secrets actually leak.","2026-09-02","\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps\u002Fcard-800x500.png",{"path":749,"title":1047,"description":1048,"published":1049,"category":768,"image":1050,"draft":772},"Supabase backup tools compared, including ours","Four kinds of Supabase backup tool, what each one actually copies, and the case where a free GitHub Action beats paying anyone, us included.","2026-09-01","\u002Fblog\u002Fsupabase-backup-tools-compared\u002Fcard-800x500.png",{"path":1052,"title":1053,"description":1054,"published":1055,"category":821,"image":1056,"draft":772},"\u002Fblog\u002Freplit-secrets-explained","How to use secrets in Replit, and what still gets published","How to use secrets in Replit: add one, read it back, and fix the two reasons it comes back undefined. Plus the keys the Secrets tool cannot keep private.","2026-08-31","\u002Fblog\u002Freplit-secrets-explained\u002Fcard-800x500.png",{"path":1058,"title":1059,"description":1060,"published":1061,"category":768,"image":1062,"draft":772},"\u002Fblog\u002Fback-up-supabase-free-tier","Supabase free tier backups: how to make one without a terminal","There are no Supabase free tier backups, so the copy has to come from you. How to make one from the dashboard, and what CSV leaves out.","2026-08-30","\u002Fblog\u002Fback-up-supabase-free-tier\u002Fcard-800x500.png",{"path":1064,"title":1065,"description":1066,"published":1067,"category":821,"image":1068,"draft":772},"\u002Fblog\u002Fis-supabase-secure","Is Supabase secure? Yes. Your project is a separate question","Is Supabase secure? The platform is audited, encrypted and pen-tested. Their own compliance documents say where that stops and your settings begin.","2026-08-29","\u002Fblog\u002Fis-supabase-secure\u002Fcard-800x500.png",{"path":1070,"title":1071,"description":1072,"published":1073,"category":821,"image":1074,"draft":772},"\u002Fblog\u002Fwhere-to-find-supabase-api-keys","Where to find your Supabase API keys: anon, service_role and the URL","Your Supabase project URL, anon key and service_role key are on one dashboard page. Here is where that page is, and which of the four belongs in your app.","2026-08-28","\u002Fblog\u002Fwhere-to-find-supabase-api-keys\u002Fcard-800x500.png",{"path":1076,"title":1077,"description":1078,"published":1079,"category":821,"image":1080,"draft":772},"\u002Fblog\u002Fnew-row-violates-row-level-security-policy","New row violates row-level security policy in Supabase. Now what?","\"New row violates row-level security policy\" means Supabase refused a write. The fix that clears it in ten seconds also reopens the table to everyone.","2026-08-27","\u002Fblog\u002Fnew-row-violates-row-level-security-policy\u002Fcard-800x500.png",{"path":1082,"title":1083,"description":1084,"published":1085,"category":821,"image":1086,"draft":772},"\u002Fblog\u002Fcors-wildcard-security-risk","Is a CORS wildcard a security risk? Usually not.","Is a CORS wildcard a security risk? Usually it is your builder default, and it gives away nothing your server was not already handing to anyone who asked.","2026-08-26","\u002Fblog\u002Fcors-wildcard-security-risk\u002Fcard-800x500.png",{"path":1088,"title":1089,"description":1090,"published":1091,"category":768,"image":1092,"draft":772},"\u002Fblog\u002Fsupabase-branching-is-not-a-backup","Supabase branching is not a backup. It only goes forwards.","Supabase branching is not a backup: a branch starts with none of your data, and merging only moves schema. What it is for, and what to use instead.","2026-08-25","\u002Fblog\u002Fsupabase-branching-is-not-a-backup\u002Fcard-800x500.png",{"path":588,"title":1094,"description":1095,"published":1096,"category":768,"image":1097,"draft":772},"How to restore a Supabase backup, and what breaks after","How to restore a Supabase backup from the dashboard or from a dump file, what the restore replaces, and why your app can still be broken when it finishes.","2026-08-24","\u002Fblog\u002Fhow-to-restore-a-supabase-backup\u002Fcard-800x500.png",{"path":1099,"title":1100,"description":1101,"published":1102,"category":821,"image":1103,"draft":772},"\u002Fblog\u002Fsupabase-storage-bucket-public","Your Supabase storage bucket is public. Is that a problem?","A public Supabase storage bucket means anyone with a file URL can open it. It does not mean anyone can list what is in there. Two different settings.","2026-08-23","\u002Fblog\u002Fsupabase-storage-bucket-public\u002Fcard-800x500.png",{"path":1105,"title":1106,"description":1107,"published":1108,"category":821,"image":1109,"draft":772},"\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend","Is a Google API key exposed in your frontend a problem?","A Google API key exposed in your frontend is the key our scanner finds most often, and usually it is fine. One free setting decides which it is.","2026-08-22","\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":1111,"title":1112,"description":1113,"published":1114,"category":768,"image":1115,"draft":772},"\u002Fblog\u002Fai-agent-deleted-my-database","An AI agent deleted my Supabase data. What can I recover?","An AI agent deleted your database data. What you can recover was decided before it ran, and the next few minutes decide how much of it survives.","2026-08-21","\u002Fblog\u002Fai-agent-deleted-my-database\u002Fcard-800x500.png",{"path":1117,"title":1118,"description":1119,"published":1120,"category":821,"image":1121,"draft":772},"\u002Fblog\u002Fcan-anyone-read-your-supabase-database","Can anyone read your Supabase database? We checked 3,680 apps","Can anyone read your Supabase database without logging in? We scanned 30,998 live apps built with AI builders and measured how often the answer is yes.","2026-08-18","\u002Fblog\u002Fcan-anyone-read-your-supabase-database\u002Fcard-800x500.png",{"path":1123,"title":1124,"description":1125,"published":1120,"category":821,"image":1126,"draft":772},"\u002Fblog\u002Fsource-maps-exposed-in-production","Source maps exposed: your app is publishing its original code","An exposed source map lets anyone read your app's original code, comments included. The 30-second check, and what actually matters if yours are public.","\u002Fblog\u002Fsource-maps-exposed-in-production\u002Fcard-800x500.png",{"path":1128,"title":1129,"description":1130,"published":1131,"category":821,"image":1132,"draft":772},"\u002Fblog\u002Fsupabase-new-api-keys","Supabase's new API keys: which one is safe in your app?","Supabase replaced anon and service_role with publishable and secret keys. Which one belongs in your app, and which never does?","2026-08-12","\u002Fblog\u002Fsupabase-new-api-keys\u002Fcard-800x500.png",{"path":1134,"title":1135,"description":1136,"published":1137,"category":768,"image":1138,"draft":772},"\u002Fblog\u002Fdoes-supabase-back-up-my-database","Does Supabase back up my database? It depends on your plan.","Does Supabase back up your database? Daily on paid plans, and not at all on the free one. How to check which you have, and what that copy cannot survive.","2026-08-11","\u002Fblog\u002Fdoes-supabase-back-up-my-database\u002Fcard-800x500.png",{"path":1140,"title":1141,"description":1142,"published":1143,"category":821,"image":1144,"draft":772},"\u002Fblog\u002Fsupabase-rls-on-but-table-still-public","Supabase Row Level Security is on. Your table is still public.","Turning on Supabase Row Level Security does not protect a table. Your policies do, and the policy that fixed your broken app may let everyone in.","2026-08-10","\u002Fblog\u002Fsupabase-rls-on-but-table-still-public\u002Fcard-800x500.png",{"path":1146,"title":1147,"description":1148,"published":1143,"category":768,"image":1149,"draft":772},"\u002Fblog\u002Fversion-history-is-not-a-backup","Version history is not a backup. It cannot undo a deleted table.","Lovable and Bolt keep version history for your code. Your database is a separate service, so rolling back to this morning does not bring your data back.","\u002Fblog\u002Fversion-history-is-not-a-backup\u002Fcard-800x500.png",{"path":1151,"title":1152,"description":1153,"published":1154,"category":768,"image":1155,"draft":772},"\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database","Three ways to back up a Supabase database, and what each misses","The dashboard, pg_dump, and a managed service. What each one actually saves, what it quietly leaves out, and which one survives losing the account.","2026-08-09","\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database\u002Fcard-800x500.png",{"path":1157,"title":1158,"description":1159,"published":1154,"category":821,"image":1160,"draft":772},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","Which API keys are safe in your frontend, and which aren't","Your Supabase anon key is supposed to be public. Your service_role key is not, and it ignores every rule you set. Here is how to tell them apart.","\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend\u002Fcard-800x500.png",1791618966336]