Building a full-stack agent? Use Neon for your backend. Apply for the Agent Plan for special pricing
/Data API

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, powered by PostgREST, offers a ready-to-use REST API for your Neon database. 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 and Neon 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.

You might notice another feature in Neon called Neon RLS. Please be aware that it's a different method for client-side querying and is not compatible with the Data API. We recommend using the Data API for client-side querying as it provides a more secure and controlled way to access your data through predefined REST endpoints.

  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

    Enabling the Data API on your branch gives you:

    • A REST API endpoint for your branch (your base URL for API requests) with a copy-to-clipboard control
    • Neon Auth as your default authentication provider (if you accept the default)
    • Two Postgres roles:
      • authenticated – used when a request includes a valid JWT
      • anonymous – will be used for unauthenticated requests (coming soon)

    Data API enabled view with REST API Endpoint

    You can change the provider to Other provider if you want to manage your own JWTs, or skip authentication setup and add it later. But if you accept the default, Neon Auth is ready to use immediately. If you select Other provider, you'll need to provide your provider's JWKS (JSON Web Key Set) URL to validate JWT tokens.

    Always secure your data before using the Data API in production.

  2. Secure your Data API

    To secure your Data API you must configure both of the following:

    • GRANT statements that define which operations (SELECT, INSERT, UPDATE, DELETE) each role can attempt
    • Row-Level Security (RLS) policies that control which specific rows each role can see or modify

    GRANT permissions

    -- 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?