Tacobase SDK Integration Guide

A step-by-step guide for adding Tacobase to your project. No backend experience required.


What You Get

Tacobase gives your app a complete backend with four building blocks:

Building blockWhat it does
AuthSign up, sign in, sign out, password reset, Google/GitHub login
DatabaseStore, read, update, and delete data (called "collections")
StorageUpload and serve files (images, PDFs, etc.)
RealtimeGet instant updates when data changes (no refreshing)

Before You Start

You need two things from the Tacobase dashboard:

  1. Your instance URL — looks like https://myapp.tacobase.dev
  2. Your API key — starts with tbk_ (e.g. tbk_abc12345_xxxxxxxxxxxxxxxx)

To get these:
1. Sign in at the Tacobase dashboard
2. Click Create Instance and give it a name
3. Once created, click into your instance
4. Click Create API Key and copy it somewhere safe — it is only shown once

You also need Node.js installed (version 18 or newer).

Step 1 — Install the SDK

Open your terminal, navigate to your project folder, and run:

bash
npm install @tacobase/client

If you're using React, also install the React helpers:

bash
npm install @tacobase/client @tacobase/react

Step 2 — Create Your Client

The "client" is the object you use to talk to tacobase. You create it once and use it everywhere.

For any JavaScript/TypeScript project

Create a file called taco.ts (or taco.js) wherever you keep your utility files:

src/lib/taco.tstypescript
import { createClient } from '@tacobase/client'

const db = createClient(
  'https://myapp.tacobase.dev',   // <-- replace with your URL
  'tbk_abc12345_xxxxxxxxxxxxxxxx' // <-- replace with your API key
)

export default db

For React projects (recommended)

Instead of importing the client everywhere, wrap your app with the TacoProvider. This gives every component access to Tacobase through hooks.

src/main.tsxtsx
import { TacoProvider } from '@tacobase/react'

function App() {
  return (
    <TacoProvider
      url="https://myapp.tacobase.dev"
      apiKey="tbk_abc12345_xxxxxxxxxxxxxxxx"
    >
      {/* Everything inside here can use Tacobase hooks */}
      <YourApp />
    </TacoProvider>
  )
}

Keep your API key out of your code

Optional but recommended

Store your URL and key in a .env file so they don't end up in git:

.env.localbash
NEXT_PUBLIC_TACOBASE_URL=https://myapp.tacobase.dev
NEXT_PUBLIC_TACOBASE_API_KEY=tbk_abc12345_xxxxxxxxxxxxxxxx

# Admin API Key (Keep this secret! Do not expose to client)
TACOBASE_ADMIN_API_KEY=tbk_xyz98765_xxxxxxxxxxxxxxxx

Then reference them in your code:

typescript
// Vite projects
const db = createClient(
  import.meta.env.VITE_TACOBASE_URL,
  import.meta.env.VITE_TACOBASE_API_KEY
)

// Next.js projects
const db = createClient(
  process.env.NEXT_PUBLIC_TACOBASE_URL!,
  process.env.NEXT_PUBLIC_TACOBASE_API_KEY!
)

Next.js TIP: Name the variables with a NEXT_PUBLIC_ prefix to make them available in the browser.

Step 3 — Add User Authentication

Option A: Drop-in Auth Form (fastest)

Use the AuthForm component for a full login/signup form with zero config.

tsx
import { AuthForm } from '@tacobase/react'

function LoginPage() {
  return (
    <AuthForm
      providers={['google', 'github']}
      onSuccess={(user) => {
        console.log('Logged in as', user.email)
        window.location.href = '/dashboard'
      }}
    />
  )
}

Option B: Build Your Own Login Form

Use the useAuth hook for full control.

Sign-up form

tsx
import { useState } from 'react'
import { useAuth } from '@tacobase/react'

function SignUpForm() {
  const { signUp } = useAuth()
  const [email, setEmail] = useState('')
  const [password, setPassword] = useState('')

  async function handleSubmit(e) {
    e.preventDefault()
    await signUp(email, password)
    // Redirect or update UI
  }

  return (
    <form onSubmit={handleSubmit}>
      <input type="email" value={email} onChange={e => setEmail(e.target.value)} required />
      <input type="password" value={password} onChange={e => setPassword(e.target.value)} required />
      <button type="submit">Sign Up</button>
    </form>
  )
}

Step 4 — Protect Pages

Show different content depending on whether the user is logged in.

tsx
import { useAuth } from '@tacobase/react'

function App() {
  const { user, loading } = useAuth()

  // Still checking if user is logged in
  if (loading) return <p>Loading...</p>

  // Not logged in
  if (!user) return <LoginPage />

  // Logged in
  return (
    <div>
      <p>Welcome, {user.email}!</p>
      <Dashboard />
    </div>
  )
}

Step 5 — Read and Write Data

Collections are like database tables. You can create them from the Tacobase dashboard or programmatically from a secure server environment using the Admin API Key, then read/write from your code.

Create a collection from code (Admin Only)

If you are running in a secure server environment (like a Node.js script or a Next.js API route), you can use the Admin API Key to automatically create your collections. Never use the admin key in client-side code.

typescript
import { createClient } from '@tacobase/client'

// 1. Initialize with your Admin API Key
const dbAdmin = createClient(
  process.env.NEXT_PUBLIC_TACOBASE_URL!, // The URL is the same
  process.env.TACOBASE_ADMIN_API_KEY!    // SECRET admin key
)

// 2. Create the collection programmatically
const newCollection = await dbAdmin.admin.createCollection({
  name: 'posts',
  type: 'base',
  schema: [
    { name: 'title', type: 'text', required: true },
    { name: 'content', type: 'editor' },
    { name: 'published', type: 'bool' }
  ]
})

console.log('Created collection:', newCollection.id)

React shortcut: useCollection hook

Fetches data and handles loading/error states automatically.

tsx
import { useCollection } from '@tacobase/react'

function PostList() {
  const { items, loading, error } = useCollection('posts', {
    sort: '-created',
    filter: 'published = true',
  })

  if (loading) return <p>Loading posts...</p>
  if (error) return <p>Error: {error.message}</p>

  return (
    <ul>
      {items.map(post => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  )
}

CRUD Operations (Vanilla JS / Handlers)

typescript
// Create
const newPost = await db.collection('posts').create({
  title: 'My First Post',
  published: true,
})

// Read (List)
const result = await db.collection('posts').getList(1, 20, {
  sort: '-created',
})

// Update
await db.collection('posts').update('RECORD_ID', {
  title: 'Updated Title',
})

// Delete
await db.collection('posts').delete('RECORD_ID')

Step 6 — Upload Files

Files are attached to records. Add a file field to your collection in the dashboard first.

typescript
const formData = new FormData()
formData.append('title', 'My photo')
formData.append('image', fileInput.files[0])

const record = await db.collection('posts').create(formData)

Get the file URL

typescript
const url = db.storage.getFileUrl(record, 'photo.jpg')

// With thumbnail transform
const thumbUrl = db.storage.getFileUrl(record, 'photo.jpg', {
  thumb: '100x100',
})

Step 7 — Listen for Live Updates

Realtime subscriptions let your app update instantly when data changes.

typescript
// Watch for any changes
const unsubscribe = await db.collection('messages').subscribe((event) => {
  console.log(event.action) // 'create', 'update', or 'delete'
  console.log(event.record) // the data that changed
})

// Stop listening
await unsubscribe()

Full Working Example

A complete React app with auth and data — ready to copy.

src/App.tsxtsx
import { TacoProvider, useAuth, useCollection, AuthForm } from '@tacobase/react'

const URL = import.meta.env.VITE_TACOBASE_URL
const KEY = import.meta.env.VITE_TACOBASE_API_KEY

export default function App() {
  return (
    <TacoProvider url={URL} apiKey={KEY}>
      <Main />
    </TacoProvider>
  )
}

function Main() {
  const { user, loading, signOut } = useAuth()

  if (loading) return <p>Loading...</p>

  if (!user) {
    return (
      <div style={{ maxWidth: 400, margin: '100px auto' }}>
        <AuthForm
          providers={['google']}
          onSuccess={() => window.location.reload()}
        />
      </div>
    )
  }

  return (
    <div style={{ maxWidth: 600, margin: '40px auto' }}>
      <h1>Welcome, {user.email}</h1>
      <button onClick={signOut}>Sign Out</button>
      <hr />
      <PostsList />
    </div>
  )
}

function PostsList() {
  const { items, loading, error } = useCollection('posts', {
    sort: '-created',
    filter: 'published = true',
  })

  if (loading) return <p>Loading posts...</p>
  if (items.length === 0) return <p>No posts yet.</p>

  return (
    <ul>
      {items.map(post => (
        <li key={post.id}>
          <strong>{post.title}</strong>
          <p>{post.content}</p>
        </li>
      ))}
    </ul>
  )
}

Quick Reference

typescript
import { createClient } from '@tacobase/client'
const db = createClient(url, apiKey)

// Auth
await db.auth.signUp({ email, password })
await db.auth.signIn({ email, password })
await db.auth.signInWithOAuth({ provider: 'google' })
await db.auth.requestPasswordReset(email)
db.auth.signOut()
db.auth.user         // current user or null
db.auth.isValid      // true if logged in
db.auth.onStateChange((event, record) => { ... })

// Database
await db.collection('x').getList(page, perPage, { filter, sort, expand })
await db.collection('x').getOne(id)
await db.collection('x').getFirstListItem(filter)
await db.collection('x').getFullList({ filter, sort })
await db.collection('x').create(data)
await db.collection('x').update(id, data)
await db.collection('x').delete(id)

// Realtime
const unsub = await db.collection('x').subscribe(callback)
await unsub()

// Storage
db.storage.getFileUrl(record, filename)
db.storage.getFileUrl(record, filename, { thumb: '100x100' })

Common Mistakes

"useTaco* hooks must be used within a TacoProvider"

Make sure <TacoProvider> wraps your entire app or at least the part that uses the hooks.

"Instance unavailable after 3 retries"

Your Tacobase instance might be stopped. Check the dashboard. The SDK retries automatically, but if it wakes up too slowly, you might see this error.

Forgetting "await"

Most SDK calls are asynchronous. If you forget await, you get a Promise instead of data.

Wrong environment variable names

Use TACOBASE_URL and TACOBASE_API_KEY (with framework prefixes like NEXT_PUBLIC_ or VITE_ for client-side code).

❌ TACOBASE_SECRET, TACOBASE_KEY, tacobase_url
✅ TACOBASE_URL, TACOBASE_API_KEY

Using platform URL instead of instance URL

The URL should point to your instance, not the platform dashboard.

❌ https://tacobase.dev
✅ https://myapp.tacobase.dev

Model Context Protocol (MCP) Server

Tacobase provides an official Model Context Protocol (MCP) server. This allows AI assistants like Cursor and Claude to directly manage your Tacobase schema and collections via natural language.

Using with Cursor

  1. Open Cursor Settings (Cmd/Ctrl + ,)
  2. Go to FeaturesMCP (Model Context Protocol)
  3. Click + Add new MCP server
  4. Configure it as follows:
    • Type: command
    • Name: tacobase-mcp
    • Command: npx
    • Args: -y @tacobase/mcp-server
  5. Add the following environment variables:
    • TACOBASE_URL: e.g. https://your-instance.tacobase.dev
    • TACOBASE_ADMIN_API_KEY: Your Admin API Key

💡 Tip: Once connected, you can ask Cursor: "Create a tasks collection with a title and a boolean completed field" and it will execute the schema modifications for you!

Using with Claude Desktop

Add the following to your claude_desktop_config.json (located via Claude Desktop settings → Developer → Edit Config):

json
{
  "mcpServers": {
    "Tacobase": {
      "command": "npx",
      "args": ["-y", "@tacobase/mcp-server"],
      "env": {
        "TACOBASE_URL": "https://your-instance.tacobase.dev",
        "TACOBASE_ADMIN_API_KEY": "tbk_xyz98765_xxxxxxxxxxxxxxxx"
      }
    }
  }
}

Restart Claude Desktop to apply the configuration.

Next Steps

  • Create collections in the dashboard to define your data structure
  • Set up collection rules to control who can read/write data
  • Enable OAuth providers in your instance's auth settings
  • Real the full API reference in the @tacobase/client README