Supabase With TypeScript: A Developer's Guide
Hey guys! Today, we're diving deep into the world of Supabase and TypeScript. If you're looking to build scalable, type-safe applications, then you've come to the right place. We'll explore how to leverage the power of Supabase as a backend with the robustness of TypeScript on the frontend. Let's get started!
Why Supabase and TypeScript?
Supabase: The Open Source Firebase Alternative
Supabase is often referred to as the open-source alternative to Firebase. It provides a suite of tools to help you build backends quickly. Think of it as a comprehensive backend-as-a-service (BaaS) platform. Here’s what makes Supabase so appealing:
- Realtime Database: Supabase uses PostgreSQL, a powerful and reliable relational database. With its realtime capabilities, your app can react instantly to data changes.
- Authentication: Supabase offers built-in authentication, making it easy to manage users with various providers like Google, GitHub, and more. You can also implement custom authentication flows.
- Storage: Storing and serving files is a breeze with Supabase's storage solution, which is built on top of Google Cloud Storage. It’s secure, scalable, and easy to use.
- Functions: Supabase allows you to deploy serverless functions written in JavaScript or TypeScript, enabling you to extend your backend logic without managing servers.
The beauty of Supabase lies in its simplicity and the fact that it's built on open standards. You're not locked into a proprietary ecosystem, giving you more control and flexibility over your data and infrastructure.
TypeScript: Adding Type Safety to JavaScript
TypeScript is a superset of JavaScript that adds static typing. This means you can catch errors during development rather than at runtime. For larger projects, this can be a game-changer. Here’s why TypeScript is awesome:
- Early Error Detection: TypeScript's static typing allows you to catch type-related errors during development, reducing the likelihood of runtime bugs.
- Improved Code Maintainability: With explicit types, your code becomes more self-documenting, making it easier to understand and maintain.
- Enhanced Code Completion: IDEs can provide better code completion and suggestions with TypeScript, improving your development workflow.
- Refactoring Support: Refactoring becomes safer and easier because TypeScript can help you identify all the places where a type change might have an impact.
TypeScript makes JavaScript development more robust and scalable, especially for complex applications. By using TypeScript, you can write more maintainable and reliable code.
The Synergy
Combining Supabase and TypeScript gives you the best of both worlds: a powerful, easy-to-use backend with a robust, type-safe frontend. This combination helps you build scalable, maintainable, and reliable applications. Using TypeScript with Supabase enhances the development experience by providing type safety across your entire stack.
Setting Up Your Project
Prerequisites
Before we dive into the code, make sure you have the following installed:
- Node.js: You'll need Node.js to run your TypeScript project.
- npm or Yarn: A package manager to install dependencies.
- Supabase Account: Sign up for a free Supabase account at supabase.com.
Creating a Supabase Project
- Sign In: Log in to your Supabase account.
- New Project: Click on "New Project" and provide the necessary details (name, region, database password).
- Database Details: Once your project is created, you'll find your project URL and API key in the project settings. You'll need these to connect to your Supabase backend.
Initializing a TypeScript Project
Let's create a new TypeScript project:
mkdir supabase-typescript-app
cd supabase-typescript-app
npm init -y
tsc --init
This will create a package.json file and a tsconfig.json file, which configures the TypeScript compiler. Open tsconfig.json and configure it as follows:
{
"compilerOptions": {
"target": "es2020",
"module": "esnext",
"moduleResolution": "node",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"outDir": "dist"
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
Installing Supabase Client
Next, install the Supabase client library:
npm install @supabase/supabase-js
npm install typescript @types/node -D
The @supabase/supabase-js package is the official Supabase client library for JavaScript and TypeScript. The other packages are TypeScript itself and type definitions for Node.js.
Connecting to Supabase
Setting Up the Client
Create a new directory named src and add a file named supabaseClient.ts:
mkdir src
touch src/supabaseClient.ts
Open src/supabaseClient.ts and add the following code:
import { createClient } from '@supabase/supabase-js';
const supabaseUrl = process.env.SUPABASE_URL || '';
const supabaseKey = process.env.SUPABASE_ANON_KEY || '';
export const supabase = createClient(supabaseUrl, supabaseKey);
Important: Store your SUPABASE_URL and SUPABASE_ANON_KEY in environment variables to keep them secure. You can set these variables in your .env file. Make sure to install the dotenv package:
npm install dotenv
Create a .env file in the root of your project:
SUPABASE_URL=your_supabase_url
SUPABASE_ANON_KEY=your_supabase_anon_key
And update your supabaseClient.ts to load the environment variables:
import { createClient } from '@supabase/supabase-js';
import * as dotenv from 'dotenv';
dotenv.config();
const supabaseUrl = process.env.SUPABASE_URL || '';
const supabaseKey = process.env.SUPABASE_ANON_KEY || '';
export const supabase = createClient(supabaseUrl, supabaseKey);
Performing CRUD Operations
Now that we have our Supabase client set up, let's perform some basic CRUD (Create, Read, Update, Delete) operations.
Creating Data
Let’s create a new file called src/create.ts to handle creating data:
touch src/create.ts
Add the following code:
import { supabase } from './supabaseClient';
async function createRecord() {
const { data, error } = await supabase
.from('your_table_name')
.insert([
{
column1: 'value1',
column2: 'value2',
},
]);
if (error) {
console.error('Error inserting data:', error);
} else {
console.log('Data inserted successfully:', data);
}
}
createRecord();
Replace your_table_name, column1, column2, value1, and value2 with your actual table and column names and desired values.
Reading Data
Create a new file called src/read.ts:
touch src/read.ts
Add the following code:
import { supabase } from './supabaseClient';
async function readRecords() {
const { data, error } = await supabase
.from('your_table_name')
.select('*');
if (error) {
console.error('Error reading data:', error);
} else {
console.log('Data read successfully:', data);
}
}
readRecords();
Replace your_table_name with the name of your table.
Updating Data
Create a new file called src/update.ts:
touch src/update.ts
Add the following code:
import { supabase } from './supabaseClient';
async function updateRecord() {
const { data, error } = await supabase
.from('your_table_name')
.update({
column1: 'new_value1',
column2: 'new_value2',
})
.eq('id', 1); // Replace 1 with the ID of the record you want to update
if (error) {
console.error('Error updating data:', error);
} else {
console.log('Data updated successfully:', data);
}
}
updateRecord();
Replace your_table_name, column1, column2, new_value1, and new_value2 with your actual table and column names and desired values. Also, replace 1 with the ID of the record you want to update.
Deleting Data
Create a new file called src/delete.ts:
touch src/delete.ts
Add the following code:
import { supabase } from './supabaseClient';
async function deleteRecord() {
const { data, error } = await supabase
.from('your_table_name')
.delete()
.eq('id', 1); // Replace 1 with the ID of the record you want to delete
if (error) {
console.error('Error deleting data:', error);
} else {
console.log('Data deleted successfully:', data);
}
}
deleteRecord();
Replace your_table_name with the name of your table. Also, replace 1 with the ID of the record you want to delete.
Running the Code
To run these scripts, add the following to your package.json file under the scripts section:
"scripts": {
"create": "ts-node src/create.ts",
"read": "ts-node src/read.ts",
"update": "ts-node src/update.ts",
"delete": "ts-node src/delete.ts"
},
Now you can run these scripts using npm run create, npm run read, npm run update, and npm run delete.
Authentication with Supabase and TypeScript
Setting Up Authentication
Supabase provides built-in authentication. Let's see how to use it with TypeScript.
Create a new file called src/auth.ts:
touch src/auth.ts
Add the following code:
import { supabase } from './supabaseClient';
async function signUp(email: string, password: string) {
const { data, error } = await supabase.auth.signUp({
email: email,
password: password,
});
if (error) {
console.error('Error signing up:', error);
} else {
console.log('Signed up successfully:', data);
}
}
async function signIn(email: string, password: string) {
const { data, error } = await supabase.auth.signInWithPassword({
email: email,
password: password,
});
if (error) {
console.error('Error signing in:', error);
} else {
console.log('Signed in successfully:', data);
}
}
async function signOut() {
const { error } = await supabase.auth.signOut();
if (error) {
console.error('Error signing out:', error);
} else {
console.log('Signed out successfully');
}
}
// Example usage:
// signUp('test@example.com', 'password123');
// signIn('test@example.com', 'password123');
// signOut();
Handling User Sessions
To manage user sessions, you can use the supabase.auth.getSession() method.
async function getSession() {
const { data: { session }, error } = await supabase.auth.getSession()
if (error) {
console.error('Error getting session:', error);
} else {
console.log('Session:', session);
}
}
getSession();
Realtime Subscriptions
Supabase’s realtime capabilities allow you to subscribe to changes in your database.
Create a new file called src/realtime.ts:
touch src/realtime.ts
Add the following code:
import { supabase } from './supabaseClient';
supabase
.channel('any')
.on(
'postgres_changes',
{ event: '*', schema: 'public', table: 'your_table_name' },
(payload) => {
console.log('Change received!', payload);
}
)
.subscribe();
Replace your_table_name with the name of your table. This code subscribes to all changes (inserts, updates, deletes) on the specified table.
Conclusion
Alright, guys, we've covered a lot! You now have a solid foundation for building applications with Supabase and TypeScript. From setting up your project and performing CRUD operations to handling authentication and using realtime subscriptions, you’re well-equipped to create scalable and type-safe applications. Keep experimenting, keep building, and happy coding!
By leveraging the power of Supabase and TypeScript, you can create robust, maintainable, and scalable applications. The combination of a powerful backend-as-a-service with the type safety of TypeScript enhances the development experience and helps you build better software.