On this page
Build Astro with Deno
Astro is a modern web framework focused on content-centric websites, which leverages islands architecture and sends zero JavaScript to the client by default. You can see the finished app on GitHub.
You can see a live version of the app on Deno Deploy.
Want to skip the tutorial and deploy the finished app right now? Click the button below to instantly deploy your own copy of the complete Astro dinosaur app to Deno Deploy. You'll get a live, working application that you can customize and modify as you learn!
Scaffold an Astro project Jump to heading
Astro provides a CLI tool to quickly scaffold a new Astro project. In your terminal, run the following command to create a new Astro project with Deno.
deno init --npm astro@latest
For this tutorial, we’ll select the “Empty” template so we can start from scratch and we'll install the dependencies.
this will set us up with a basic Astro project structure, including a
package.json
file, and a src
directory where our application code will live.
Start the Astro server Jump to heading
We can start the local Astro server with the dev
task. In your terminal,
change directory into your new project and run run
deno task dev
This will start the Astro development server, which will watch for changes in
your files and automatically reload the page in your browser. You should see a
message indicating that the server is running on http://localhost:4321
.
Upon visiting the output URL in your browser, you should see a very basic Astro welcome page.
Build out the app architecture Jump to heading
Now that we have a basic Astro project set up, let's build out the architecture of our app. We'll create a few directories to organize our code and set up some basic routing. Create the following directories
src/
├── data/
├── lib/
└── pages/
└── index.astro
Add dinosaur data Jump to heading
In the data
directory, create a new file called data.json
file, which will
contain the hard coded dinosaur data.
Copy and paste
this json file
into the data.json
file. (If you were building a real app, you would probably
fetch this data from a database or an external API.)
Set up the business logic Jump to heading
Next, we’ll create a lib
directory to hold our business logic. In this case,
we’ll create a file called dinosaur-service.ts
that will contain a function to
fetch the dinosaur data. Create src/lib/dinosaur-service.ts
with the following
code:
// Simple utility functions for working with dinosaur data
import dinosaursData from "../data/data.json";
export interface Dinosaur {
name?: string;
description: string;
}
export class DinosaurService {
private static dinosaurs: Dinosaur[] = dinosaursData;
// Get all dinosaurs with names (filter out unnamed ones)
static getNamedDinosaurs(): Dinosaur[] {
return this.dinosaurs.filter((dino) => dino.name);
}
// Create a URL-friendly slug from dinosaur name
static createSlug(name: string): string {
return name
.toLowerCase()
.replace(/[^a-z0-9]+/g, "-")
.replace(/^-+|-+$/g, "");
}
// Get dinosaur by slug
static getDinosaurBySlug(slug: string): Dinosaur | undefined {
return this.dinosaurs.find((dino) => {
if (!dino.name) return false;
return this.createSlug(dino.name) === slug;
});
}
// Get all dinosaurs with their slugs for linking
static getDinosaursWithSlugs() {
return this.getNamedDinosaurs().map((dino) => ({
...dino,
slug: this.createSlug(dino.name!),
}));
}
}
export default DinosaurService;
This file contains a DinosaurService
class with methods to get all dinosaurs,
create a URL-friendly slug from a dinosaur name, and get a dinosaur by its slug.
Update the index page to use the service Jump to heading
Now we can update our index.astro
page to use the DinosaurService
to fetch
the dinosaur data and render it as a list of links. Update the
src/pages/index.astro
file to look like this:
---
import DinosaurService from '../lib/dinosaur-service';
import '../../styles/index.css';
// Get all dinosaurs with slugs for linking
const dinosaursWithSlugs = DinosaurService.getDinosaursWithSlugs();
---
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<title>Dinosaur Directory</title>
</head>
<body>
<h1>🦕 Dinosaur Directory</h1>
<p>Click on any dinosaur name to learn more about it!</p>
<div class="dinosaur-list">
{dinosaursWithSlugs.map((dinosaur) => (
<a href={`/dinosaur/${dinosaur.slug}`} class="dinosaur-link">
{dinosaur.name}
</a>
))}
</div>
</body>
</html>
We import the DinosaurService
, then map over the dinosaurs to create links to
individual dinosaur pages.
Create individual dinosaur pages Jump to heading
Next, we’ll create individual pages for each dinosaur. In the src/pages
directory, create a directory called dinosaurs
, and inside that directory,
create a file called [slug].astro
. This file will be used to render the
individual dinosaur pages:
---
import DinosaurService from '../../lib/dinosaur-service';
import '../../styles/index.css';
export async function getStaticPaths() {
const dinosaursWithSlugs = DinosaurService.getDinosaursWithSlugs();
return dinosaursWithSlugs.map((dinosaur) => ({
params: { slug: dinosaur.slug },
props: { dinosaur }
}));
}
const { dinosaur } = Astro.props;
---
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<title>{dinosaur.name} - Dinosaur Directory</title>
<meta name="description" content={dinosaur.description} />
<link rel="stylesheet" href="https://demo-styles.deno.deno.net/styles.css">
</head>
<body class="dinosaur">
<main>
<h1>🦕 {dinosaur.name}</h1>
<div class="info-card">
<p>{dinosaur.description}</p>
</div>
<a href="/" class="btn-secondary">Back to Directory</a>
</main>
</body>
</html>
This file uses the getStaticPaths
function to generate static paths for each
dinosaur based on the slugs we created earlier. The Astro.props
object will
contain the dinosaur data for the specific slug, which we can then render in the
page.
Add some styles Jump to heading
You can style your app to make it your own in the src/styles/index.css
. This
file is imported in both the index.astro
and [slug].astro
files, so any
styles you add here will apply to both pages.
Build and deploy Jump to heading
Astro has a built-in command to build your site for production:
deno run build
This will:
- Generate static HTML files for each page in the
dist
directory. - Optimize your assets (CSS, JavaScript, images, etc.) for production.
You can deploy this app to your favorite cloud provider. We recommend using Deno Deploy for a simple and easy deployment experience. You can deploy your app directly from GitHub, simply create a GitHub repository and push your code there, then connect it to Deno Deploy.
Create a GitHub repository Jump to heading
Create a new GitHub repository, then initialize and push your app to GitHub:
git init -b main
git remote add origin https://github.com/<your_github_username>/<your_repo_name>.git
git add .
git commit -am 'initial commit'
git push -u origin main
Deploy to Deno Deploy Jump to heading
Once your app is on GitHub, you can deploy to Deno DeployEA dashboard.
For a walkthrough of deploying your app, check out the Deno Deploy tutorial.
🦕 Now you can scaffold and develop an Astro app that will run on Deno! You could extend this app by adding more features, such as user authentication, a database, or even a CMS. We can’t wait to see what you build with Astro and Deno!