Astro + Turso: The Perfect Pair for Building Fast, Scalable Websites

- Introduction
- Astro
- Turso
- Initial Setup
- Building the Website with Astro
- Creating a Database and Table with Turso CLI
- 0. Install Turso CLI and Login
- 1. Create a New Database
- 2. Access the Database Shell
- 3. Create the posts Table
- 4. Retrieve the Database URL
- 5. Generate a Read/Write Authentication Token
- Integrating Turso with Astro
- Interacting with the Database
- Fetching Data in Astro
- Index Page
- Post Page
- Further Developments
Introduction
In this article, we’ll show you how to use Astro and Turso together to build fast, scalable content-driven websites.
When building a modern website, developers often prioritize speed, ease of content management, and a seamless user experience. Astro and Turso are two tools that cater to these needs effectively, providing robust frameworks for developing content-driven websites that are both fast and scalable.
Astro
Astro is an open-source web framework designed specifically for building content-heavy websites such as blogs, e-commerce sites, and marketing pages. It follows a unique server-first rendering model that minimizes client-side JavaScript, which makes it highly performant by default. This is achieved through its island architecture, where only specific components are hydrated and rendered on the client-side, reducing overall page load times and improving SEO performance. Additionally, Astro is framework-agnostic, allowing developers to use components from popular JavaScript frameworks like React, Vue, Svelte, and others, making it flexible and easy to integrate into existing projects.
Astro also supports both Static Site Generation (SSG) and Server-Side Rendering (SSR), giving developers control over how content is generated and delivered. This makes Astro a versatile option for projects that range from static blogs to more dynamic web applications that need real-time updates. For more details on Astro’s capabilities, you can check out their official documentation.
Turso
Turso is a distributed database platform built on SQLite, known for its lightweight footprint and efficiency. Turso extends SQLite’s capabilities by supporting distributed data storage and retrieval, which makes it ideal for managing content across multiple regions with low-latency access. This setup is particularly useful for modern web applications that need to deliver content quickly and efficiently to users around the world.
By leveraging SQLite, Turso maintains compatibility with an array of existing tools and workflows, while its edge-oriented architecture ensures fast data access and real-time updates. This enables Astro to efficiently handle dynamic content, supporting real-time data fetching and server-side rendering without sacrificing performance. For more information on Turso’s SQLite integration and its benefits, check out the Turso documentation and additional insights on distributed data handling.
Turso can handle dynamic data efficiently and support Astro’s SSR capabilities to deliver up-to-date content without compromising speed. This combination makes Astro and Turso a powerful duo for developers looking to create fast, responsive, and scalable content-driven websites.
Initial Setup
Building the Website with Astro
Let’s start by creating a new Astro project.
Copynpm create astro@latest
Follow the prompts to set up your project. Once the project is created, navigate into the project directory and install the dependencies.
Copycd your-project-name npm install
Note that we are using the template with sample files. We will not be building front-end components in this tutorial. You should see the following directory structure (skipping files that are not relevant to this tutorial).
Copyyour-project-name/ ├── node_modules/ ├── public/ ├── src/ │ ├── components/ │ └── Card.astro │ ├── layouts/ │ └── Layout.astro │ └── pages/ └── └── index.astro
Creating a Database and Table with Turso CLI
0. Install Turso CLI and Login
Install Turso CLI: If you haven’t already, install the Turso CLI on your system. Instructions for installation are available on Turso’s documentation.
Then login to your Turso account:
Copyturso auth login
1. Create a New Database
To create a new database, run:
Copyturso db create my-database
Turso will create the database in the nearest location based on your IP.
2. Access the Database Shell
After creating your database, access it using:
Copyturso db shell my-database
3. Create the posts
Table
Inside the Turso database shell, create a table called posts
:
CopyCREATE TABLE posts ( slug TEXT PRIMARY KEY, title TEXT NOT NULL, body TEXT NOT NULL );
This creates a table with slug as the primary key and both title and body columns as required fields.
Verify that the table was created successfully and add dummy data:
CopySELECT * FROM posts; INSERT INTO posts (slug, title, body) VALUES ('my-first-post', 'My First Post', 'This is the first post.'), ('my-second-post', 'My Second Post', 'Is the 2nd one better?'), ('my-third-post', 'My Third Post', 'Practice makes perfect.');
Then exit the db shell:
Copy.quit
4. Retrieve the Database URL
To retrieve the database URL, run:
Copyturso db show my-database --url
Store it a the .env
file at the root of the project.
Copy├── node_modules/ ├── public/ ├── src/ │ ├── components/ │ └── Card.astro │ ├── layouts/ │ └── Layout.astro │ └── pages/ │ └── index.astro └── .env
Copy# .env TURSO_URL="libsql://something.turso.io"
5. Generate a Read/Write Authentication Token
To allow external applications to access your database, generate a read/write token:
Copyturso db tokens create my-database
This command will output a token that you can use to connect your application to the database securely. Add it to the .env
file at the root of the project.
Copy# .env TURSO_URL="libsql://my-database-username.turso.io" TURSO_AUTH=some.long.string
Integrating Turso with Astro
Interacting with the Database
We will now create a new file src/lib/db.ts
to interact with the Turso database. But first we need to install @libsql/client
to interact with the database and dotenv
to load the environment variables from our .env
file.
Copynpm install @libsql/client dotenv
Copy// src/lib/db.ts import { createClient } from '@libsql/client'; // Load environment variables from .env file for local development import dotenv from 'dotenv'; dotenv.config(); export interface Post { slug: string; title: string; body: string; } async function queryDatabase(client: { execute: (arg0: string) => any; }, query: string) { try { const result = await client.execute(query); return result; } catch (error) { console.error('Error querying the database:', error); } } async function getClient() { const tursoUrl = process.env.TURSO_URL; if (!tursoUrl) { throw new Error('TURSO_URL is not defined in the environment variables'); } const tursoAuth = process.env.TURSO_AUTH; if (!tursoAuth) { throw new Error('TURSO_AUTH is not defined in the environment variables'); } return createClient({ url: tursoUrl, authToken: tursoAuth, }); } function mapResultToObjects(result: any) { const { columns, rows } = result; return rows.map((row: any) => { const obj: any = {}; columns.forEach((col: string) => { obj[col] = row[col]; }); return obj; }); } export async function getAllPosts():Promise<Post[]> { const client = await getClient(); const data = await queryDatabase(client, 'SELECT * FROM posts'); if (data) { const posts: Post[] = mapResultToObjects(data); return posts; } console.error('No posts found'); return []; }
Fetching Data in Astro
Now we will fetch the posts from the Turso database and display them on our index page and create a new page to display the content of a single post.
Index Page
In src/pages/index.astro
, we will add the following code to fetch the posts from the Turso database and display them on the page.
Copy--- // src/pages/index.astro import Card from '../components/Card.astro'; // Fetch posts from the Turso database import { getAllPosts } from '../lib/db'; const posts = await getAllPosts(); --- <div> <h1>My Blog</h1> <div class="grid"> {posts.map((post:Post) => ( <Card href={`/posts/${post.slug}`} title={post.title} body={post.body} /> ))} </div> </div>
Post Page
We will create a new file src/pages/[slug].astro
to display the content of a single post.
Copy--- // src/pages/[slug].astro import { getAllPosts, type Post } from '../../lib/utils/db'; export async function getStaticPaths() { const posts = await getAllPosts(); return posts.map((post: Post) => ({ params: { slug: post.slug }, props: post, })); } export async function get({ props }: { props: any }) { return { props, }; } --- <div> <h1>{Astro.props.title}</h1> <p>{Astro.props.body}</p> </div>
And Voila!, we have a fully functional blog site that fetches its content from a Turso database.
Note that in the current setup we are using Static Site Generation (SSG) to fetch the posts at build time. Depending on the use case, we could go two ways:
- Trigger a new static build when a post is created or updated, using a webhook for example.
- Use a serverless function to fetch the posts on each request.
We could also fetch the posts at build time but use SSR to fetch data from a comments
table on each request for example.
Further Developments
A natural next step would be to add a comments
table to the database and use SSR to fetch the comments for a given post on each request. We could then use client side JavaScript to add comments to the posts.
If traditional database tools are not practical enough, we could also develop an admin panel to manage the content of the blog. We could use again some client side JavaScript to add/update/delete content from the database.
We could also connect other services to the Turso database, like a python script to write new posts to the database.