Postgres 18 just shipped, and it’s already available on Neon. Deploy it in seconds and try the new features
/Data API/Get started

Getting started with Neon Data API

beta

Beta

Neon Data API is in beta and ready to use. We're actively improving it based on feedback from developers like you. Share your experience in our Discord or via the Neon Console.

The Neon Data API offers a ready-to-use REST API for your Neon database that's compatible with PostgREST. You can interact with any table, view, or function using standard HTTP verbs (GET, POST, PATCH, DELETE). To simplify querying, use client libraries like postgrest-js, postgrest-py, or postgrest-go:

const { data } = await client.from('posts').select('*');

About RLS

When using the Data API, it is essential to set up RLS policies so that you can safely expose your databases to clients such as web apps. Make sure that all of your tables have RLS policies, and that you have carefully reviewed each policy.

  1. Enable the Data API

    Enable the Data API at the branch level for a single database.

    To get started, open the Data API page from the project sidebar and click Enable.

    Data API page with enable button

    Once enabled, you'll get:

    • A REST API endpoint for your branch
    • Neon Auth as your auth provider
    • Two Postgres roles: authenticated and anonymous (coming soon)
    • GRANT permissions applied to the authenticated role

    You can customize the auth provider and GRANTs later, or choose your own auth provider during setup.

    Data API enabled view with REST API Endpoint

  2. Secure your Data API

    The Data API requires two layers of security:

    1. Database permissions (GRANT statements, already configured if you accepted the defaults)
    2. Row-Level Security (RLS) policies

    Database permissions

    If you accepted the defaults during setup, Neon automatically applied the necessary GRANT statements. If you skipped that step, you'll need to run these SQL statements manually:

    -- For existing tables
    GRANT SELECT, UPDATE, INSERT, DELETE ON ALL TABLES
      IN SCHEMA public TO authenticated;
    
    -- For future tables
    ALTER DEFAULT PRIVILEGES IN SCHEMA public
      GRANT SELECT, UPDATE, INSERT, DELETE ON TABLES TO authenticated;
    
    -- For sequences (for identity columns)
    GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO authenticated;
    
    -- Schema usage
    GRANT USAGE ON SCHEMA public TO authenticated;

    Authentication required

    All requests to the Data API currently require authentication with a valid JWT token. Anonymous access is not supported yet, but is coming soon. In the near future, we'll provide public/long-lived tokens for anonymous users.

    Create a table with RLS

    Here's a sample posts table secured with RLS. The GRANT statements above give authenticated users access to all tables, which allows the Data API to work. RLS policies then control which specific rows each user can see and modify.

    For guidance on writing RLS policies, see our PostgreSQL RLS tutorial for the basics, or our recommended Drizzle RLS guide for a simpler approach.

    SQL
    Drizzle (crudPolicy)
    Drizzle (pgPolicy)
    CREATE TABLE "posts" (
    	"id" bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    	"userId" text DEFAULT (auth.user_id()) NOT NULL,
    	"content" text NOT NULL,
    	"published" boolean DEFAULT false NOT NULL
    );
    
    -- Enable RLS and create policies
    ALTER TABLE "posts" ENABLE ROW LEVEL SECURITY;
    
    -- When RLS is enabled, all operations are denied by default unless explicitly allowed by policies.
    
    CREATE POLICY "Allow authenticated users to read any post" ON "posts"
    AS PERMISSIVE FOR SELECT TO "authenticated"
    USING (true);
    
    CREATE POLICY "Allow authenticated users to insert their own posts" ON "posts"
    AS PERMISSIVE FOR INSERT TO "authenticated"
    WITH CHECK ((select auth.user_id() = "userId"));
    
    CREATE POLICY "Allow authenticated users to update their own posts" ON "posts"
    AS PERMISSIVE FOR UPDATE TO "authenticated"
    USING ((select auth.user_id() = "userId"))
    WITH CHECK ((select auth.user_id() = "userId"));
    
    CREATE POLICY "Allow authenticated users to delete their own posts" ON "posts"
    AS PERMISSIVE FOR DELETE TO "authenticated"
    USING ((select auth.user_id() = "userId"));

    The auth.user_id() function is provided by the Data API and extracts the user ID from JWT tokens, making it available to your RLS policies for enforcing per-user access control.

    With the posts table and its RLS policies in place, you can now securely query and modify posts using the Data API.

  3. Query from your app

    The Neon Auth SDK (Stack Auth) manages JWT tokens automatically. Here's an example showing how to use it with postgrest-js:

    import { PostgrestClient } from '@supabase/postgrest-js';
    import { useUser } from '@stackframe/stack';
    
    // Example: fetch notes for the current user
    async function fetchUserNotes() {
      const user = useUser(); 
      if (!user) return null;
    
      const { accessToken } = await user.getAuthJson(); 
      const pg = new PostgrestClient(import.meta.env.VITE_DATA_API_URL, {
        headers: { Authorization: `Bearer ${accessToken}` },
      });
    
      const { data, error } = await pg
        .from('notes')
        .select('id, title, created_at, owner_id, shared')
        .eq('owner_id', user.id) 
        .order('created_at', { ascending: false }); 
    
      return { data, error };
    }

    This example shows the key steps:

    1. Get the current user with useUser()
    2. Extract their JWT token with user.getAuthJson()
    3. Create a PostgrestClient with proper authentication headers
    4. Query the Data API with filtering (.eq('owner_id', user.id)) and ordering (.order('created_at', { ascending: false }))

    To see a complete, working example of an application built with the Data API, Neon Auth, and Postgres RLS, check out our demo note-taking app:

  4. Refresh schema cache

    When you modify your database schema (adding tables, columns, or changing structure), the Data API needs to refresh its cache.

    • Console: go to Data API section and click Refresh schema cache
    • SQL: run NOTIFY pgrst, 'reload schema';

Last updated on

Was this page helpful?