Introduction
Cloud Spanner is Google's globally consistent distributed database. It combines the horizontal scalability of NoSQL databases with the transactional consistency of relational databases. This tutorial walks you through integrating it into a Node.js API step by step. You will learn how to configure the client, create a schema, and perform CRUD operations. Ideal for applications requiring global high availability.
Prerequisites
- Google Cloud account with billing enabled
- Node.js 18 or higher
- Basic knowledge of TypeScript and SQL
- gcloud CLI installed and authenticated
Project Initialization
mkdir spanner-api && cd spanner-api
npm init -y
npm install @google-cloud/spanner express typescript @types/express ts-nodeThis command creates the project and installs the official Cloud Spanner client along with Express for the REST API.
Spanner Client Configuration
import { Spanner } from '@google-cloud/spanner';
const spanner = new Spanner({
projectId: 'votre-projet-id',
keyFilename: './service-account.json'
});
export const instance = spanner.instance('spanner-instance');
export const database = instance.database('ma-base-de-donnees');The client is initialized with service account credentials. Always use a dedicated JSON file and never hardcode keys in the code.
Database and Schema Creation
import { database } from './spanner';
async function createDatabase() {
const schema = [
`CREATE TABLE Users (
UserId INT64 NOT NULL,
Email STRING(255) NOT NULL,
CreatedAt TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true)
) PRIMARY KEY (UserId)`
];
const [operation] = await database.create({ schema });
await operation.promise();
console.log('Base de données créée');
}
createDatabase();This script creates the database and the Users table. Spanner requires a primary key and uses specific types such as INT64 and TIMESTAMP.
Data Insertion
import { database } from './spanner';
async function insertUser(userId: number, email: string) {
const table = database.table('Users');
await table.insert({
UserId: userId,
Email: email,
CreatedAt: 'spanner.commit_timestamp()'
});
console.log('Utilisateur inséré');
}
insertUser(1, 'test@example.com');Insertion uses the client's insert method. The commit timestamp is handled automatically by Spanner for consistency.
Data Querying
import { database } from './spanner';
async function getUsers() {
const [rows] = await database.run({
sql: 'SELECT UserId, Email FROM Users WHERE UserId = @id',
params: { id: 1 }
});
console.log(rows.map(row => row.toJSON()));
}
getUsers();Parameterized queries prevent SQL injection and are the recommended approach on Spanner.
Complete Express API
import express from 'express';
import { database } from './spanner';
const app = express();
app.use(express.json());
app.get('/users/:id', async (req, res) => {
const [rows] = await database.run({
sql: 'SELECT * FROM Users WHERE UserId = @id',
params: { id: parseInt(req.params.id) }
});
res.json(rows.map(r => r.toJSON()));
});
app.listen(3000, () => console.log('API démarrée sur 3000'));This server exposes a simple GET route that queries Spanner. Compile with tsc before deployment.
Best Practices
- Always use parameterized queries
- Manage sessions and transactions explicitly for complex operations
- Enable monitoring via Cloud Monitoring
- Separate environments with distinct instances
- Enable encryption at rest by default
Common Errors to Avoid
- Forgetting to enable the Spanner API in the Google Cloud project
- Using incorrect SQL types (INT instead of INT64)
- Failing to configure a service account with the correct roles
- Ignoring latency for database creation operations
Further Reading
Deepen your skills with our Cloud Spanner training.