
Short answer: A Supabase RSS feed is an Edge Function that reads your published rows, builds RSS 2.0 XML with escaped text and absolute links, and returns it with the content type application/rss+xml. Deploy it with JWT verification switched off so that feed readers can open it without a token, allow public reads of published rows with a row level security policy, and add a short cache header. Then paste the function address into an auto-poster, and every new row marked as published is shared on social media automatically.
Supabase gives you a Postgres database, authentication, storage and serverless functions in one project. Many small sites and apps keep their posts in a Supabase table, but the platform has no built-in feed. An Edge Function fills the gap in about forty lines. This guide shows the table, the security policy, the function, the deployment flag that people most often forget and the checks that keep the feed reliable. At the end you will see how to share each item automatically.
An RSS feed is an HTTP response that contains XML. Supabase Edge Functions are small server-side functions written in TypeScript and run on Deno, so they can answer a GET request at a public address and talk to your database with the official client library. There is no server to manage, and the feed address stays stable while your front end changes. If your content lives in a system without a native feed, the idea is the same as in auto-posting from a headless CMS without native RSS: build the feed yourself and let the auto-poster read it.
Create a table named posts with the columns id, slug, title, summary, image, published_at y status. Row level security is enabled by default on tables created in the dashboard, and with it enabled nobody can read rows until a policy allows it. For a public blog, add a policy that lets everyone select only published rows:
alter table posts enable row level security;
create policy "Public can read published posts"
on posts for select
using (status = 'published');This keeps drafts private even if someone calls the database directly. The function uses the public (anon) key, so it can only see what the policy allows. Do not use the service role key in a public feed: it bypasses row level security, and a mistake in the query could expose drafts.
Create the function with the Supabase command line tool, for example supabase functions new rss, and put this code in supabase/functions/rss/index.ts:
import { createClient } from 'npm:@supabase/supabase-js@2';
const SITE = 'https://www.example.com';
const esc = (value: string | null) => (value ?? '')
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>');
Deno.serve(async () => {
const supabase = createClient(
Deno.env.get('SUPABASE_URL')!,
Deno.env.get('SUPABASE_ANON_KEY')!
);
const { data, error } = await supabase
.from('posts')
.select('id, slug, title, summary, image, published_at')
.eq('status', 'published')
.order('published_at', { ascending: false })
.limit(20);
if (error) {
return new Response('Feed temporarily unavailable', {
status: 503,
headers: { 'Retry-After': '120', 'Content-Type': 'text/plain' },
});
}
const items = (data ?? []).map((post) => {
const link = SITE + '/blog/' + post.slug;
const image = post.image ? new URL(post.image, SITE).href : '';
return '<item>'
+ '<title>' + esc(post.title) + '</title>'
+ '<link>' + esc(link) + '</link>'
+ '<guid isPermaLink="false">post-' + post.id + '</guid>'
+ '<pubDate>' + new Date(post.published_at).toUTCString() + '</pubDate>'
+ '<description>' + esc(post.summary) + '</description>'
+ (image ? '<enclosure url="' + esc(image) + '" type="image/jpeg" length="0"/>' : '')
+ '</item>';
});
const xml = '<?xml version="1.0" encoding="UTF-8"?>'
+ '<rss version="2.0"><channel>'
+ '<title>Example Blog</title>'
+ '<link>' + SITE + '/blog</link>'
+ '<description>News and articles from Example</description>'
+ items.join('')
+ '</channel></rss>';
return new Response(xml, {
headers: {
'Content-Type': 'application/rss+xml; charset=utf-8',
'Cache-Control': 'public, max-age=300',
},
});
});The environment variables SUPABASE_URL y SUPABASE_ANON_KEY are provided to Edge Functions by the platform, so you do not have to configure them for the hosted project. The function address has the form https://your-project-ref.supabase.co/functions/v1/rss.
This is the step that most often breaks a feed. By default Supabase checks that every request to a function carries a valid JWT in the Authorization header. A feed reader or auto-poster sends no such header, so it receives a 401 error and reports the feed as broken. For a public feed, turn verification off for this function only. You can pass the flag when you deploy, as in supabase functions deploy rss --no-verify-jwt, or set verify_jwt = false for the function in your config.toml. Keep verification on for every function that is not meant to be public.
After deployment, request the address with curl -i and confirm that the status is 200. The method is explained in debugging an RSS feed with curl, and the meaning of other status codes is covered in RSS feed HTTP status codes explained.
The helper esc converts ampersands and angle brackets into entities. Without it, a title such as “Tips & tricks” produces invalid XML and many readers stop at the first error. If your summaries contain HTML, escape them or wrap them in CDATA; the rules are in CDATA and HTML in RSS descriptions.
The query filters on status and sorts by published_at, newest first, with a limit of 20. A short feed is fetched faster, and sorting by the publication date prevents an edited old post from jumping to the top. The GUID uses the row ID, which never changes. If you used the slug and later renamed a post, an auto-poster could share it twice; see why your RSS feed auto-posts the same article twice. Dates use toUTCString(), which produces the RFC 822 format that RSS expects, as described in RSS date formats and pubDate errors.
Items are read outside your website, so every address must be complete. Relative links and image paths fail in a reader or on a social network. If your images live in Supabase Storage, store the full public address in the table or build it from the project address, and pass it through new URL(path, SITE) as in the example. Problems of this kind are described in relative URLs in RSS feeds. Choose images about 1200 pixels wide; sizes for each network are listed in social media image sizes.
Functions are billed and limited by use, and a feed is requested constantly by readers, crawlers and auto-posters. The Cache-Control header in the example allows browsers and a CDN in front of the function to reuse the response for five minutes. You can also keep a copy of the generated XML in a table or in storage and refresh it with a scheduled job, so that most requests never run a query. Keep the lifetime short: a feed cached for a day delays every share by a day. If the feed is requested very often, check the usage limits of your plan on the Supabase pricing page before launch.
Edge Functions can read query parameters, so one function can serve several feeds. Read new URL(req.url).searchParams.get('category') and add .eq('category', category) to the query when the value exists. Only accept values from a list you control, and keep the same XML builder for every feed. Separate feeds let you send news to one channel, tutorials to another and announcements to a team chat. The idea is explained in category filtering for auto-posting.
The default function address contains your project reference, which is fine for an auto-poster but not very friendly. If you want a cleaner address such as /rss.xml on your own domain, place a redirect or a rewrite in front of the function at your web host or CDN, and make sure it forwards the request without changing the content type or adding a login step. Pick one final address and keep it stable. If you later move the feed, leave a permanent redirect at the old address, because every reader and auto-poster that stored it will keep asking for it. Do not use the temporary preview address of a front-end deployment as the feed address; those addresses change and may require a login.
curl -i and check the status, the content type and the cache header.The platform is documented at supabase.com/docs.
PostRSS has been publishing RSS and Atom feeds to social networks since 2014. Paste the address of your function, connect your accounts and choose how each post is built from the title, the description or the page title. PostRSS checks the feed as often as every minute and shares each new post, with its image and link, to the channels you choose among 66 supported networks, messengers, team chats and blogs, including LinkedIn, X, Bluesky, Mastodon and Telegram. Keyword filters, UTM parameters, hashtags from categories and posting windows let you tune each channel, and the REST API and webhooks connect PostRSS to your own systems. See the PostRSS features page and the plan limits on the pricing page. More developer guides are under the Technical Guide tag.
A Supabase RSS feed is one Edge Function. Read published rows with the anon key and a row level security policy, escape every text value, use the row ID as the GUID, make links and images absolute and return the content type application/rss+xml with a short cache lifetime. Deploy the function with JWT verification off, answer failures with a 503 status and validate the result once. After that, every row you publish can reach your social channels automatically.
No. Supabase provides the database and functions, and you build the feed yourself. An Edge Function that returns RSS XML from your table is the simplest way.
By default a function requires a valid JWT. Feed readers do not send one. Deploy the function with the no verify jwt flag, or set verify_jwt to false for that function in the configuration file.
Most often row level security is enabled and no policy allows public reads, or the status filter does not match the stored value. Check the policy and the values in the status column.
Yes, if the data model allows it. Read a site or category parameter from the query string, validate it against a fixed list and build the links from a matching base address.
Yes. Paste the public function address as a source in PostRSS, connect your social accounts and each new item is posted automatically. Make sure the address opens without a login first.
What changed in the networks, what broke, and how to fix it before it costs you reach.
Creadas por Internet Solutions, el equipo detrás de PostRSS. Cada una te ahorra tiempo a su manera.