Skip to content

React

This guide shows how to integrate Butterbase into a React application using the @butterbase/sdk.

  1. Create a React project

    Terminal window
    npm create vite@latest my-app -- --template react-ts
    cd my-app
    npm install
  2. Install the SDK

    Terminal window
    npm install @butterbase/sdk
  3. Create a Butterbase client

    src/lib/butterbase.ts
    import { createClient } from '@butterbase/sdk';
    export const butterbase = createClient({
    appId: import.meta.env.VITE_BUTTERBASE_APP_ID,
    apiUrl: import.meta.env.VITE_BUTTERBASE_API_URL,
    });
  4. Set up environment variables

    .env.local
    VITE_BUTTERBASE_APP_ID=app_abc123
    VITE_BUTTERBASE_API_URL=https://api.butterbase.ai
  5. Add authentication

    src/components/Auth.tsx
    import { useState } from 'react';
    import { butterbase } from '../lib/butterbase';
    export function Auth() {
    const [email, setEmail] = useState('');
    const [password, setPassword] = useState('');
    const handleSignUp = async () => {
    const { data, error } = await butterbase.auth.signUp({ email, password });
    if (error) console.error(error);
    else console.log('Signed up:', data);
    };
    const handleSignIn = async () => {
    const { data, error } = await butterbase.auth.signIn({ email, password });
    if (error) console.error(error);
    else console.log('Signed in:', data);
    };
    return (
    <div>
    <input
    type="email"
    value={email}
    onChange={(e) => setEmail(e.target.value)}
    placeholder="Email"
    />
    <input
    type="password"
    value={password}
    onChange={(e) => setPassword(e.target.value)}
    placeholder="Password"
    />
    <button onClick={handleSignUp}>Sign Up</button>
    <button onClick={handleSignIn}>Sign In</button>
    </div>
    );
    }
  6. Query and display data

    src/components/Posts.tsx
    import { useEffect, useState } from 'react';
    import { butterbase } from '../lib/butterbase';
    interface Post {
    id: string;
    title: string;
    body: string;
    created_at: string;
    }
    export function Posts() {
    const [posts, setPosts] = useState<Post[]>([]);
    useEffect(() => {
    async function fetchPosts() {
    const { data, error } = await butterbase
    .from<Post>('posts')
    .select('*')
    .order('created_at', { ascending: false })
    .limit(20);
    if (data) setPosts(data);
    }
    fetchPosts();
    }, []);
    const handleCreate = async () => {
    const { data, error } = await butterbase
    .from('posts')
    .insert({ title: 'New Post', body: 'Hello from React!' });
    if (data) setPosts((prev) => [data, ...prev]);
    };
    return (
    <div>
    <button onClick={handleCreate}>Create Post</button>
    {posts.map((post) => (
    <div key={post.id}>
    <h2>{post.title}</h2>
    <p>{post.body}</p>
    </div>
    ))}
    </div>
    );
    }
  7. Handle auth state changes

    src/App.tsx
    import { useEffect, useState } from 'react';
    import { butterbase } from './lib/butterbase';
    import { Auth } from './components/Auth';
    import { Posts } from './components/Posts';
    function App() {
    const [user, setUser] = useState(null);
    useEffect(() => {
    // Check for existing session
    butterbase.auth.getUser().then(({ data }) => {
    if (data) setUser(data);
    });
    // Listen for auth changes
    const { unsubscribe } = butterbase.onAuthStateChange((event, session) => {
    setUser(session?.user ?? null);
    });
    return () => unsubscribe();
    }, []);
    return (
    <div>
    {user ? <Posts /> : <Auth />}
    </div>
    );
    }
    export default App;
  8. Deploy your frontend

    Terminal window
    npm run build
    node zip-dist.js # or: cd dist && zip -r ../frontend.zip .

    Then use the create_frontend_deployment and start_frontend_deployment MCP tools to deploy.

const handleGoogleSignIn = () => {
const { url } = butterbase.auth.signInWithOAuth({
provider: 'google',
redirectTo: window.location.origin + '/auth/callback'
});
window.location.href = url;
};
const handleUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file) return;
const { data, error } = await butterbase.storage.upload(file);
if (data) {
// Save data.objectId in your database
console.log('Uploaded:', data.objectId);
}
};
const result = await butterbase.functions.invoke('send-notification', {
body: { userId: '123', message: 'Hello!' },
method: 'POST'
});