Get up and running with Lynkow in under 10 minutes. This guide walks you through installing the SDK, connecting to your site, and fetching your first content.
Prerequisites
Before you begin, make sure you have:
Node.js 18+ installed (download)
A Lynkow account with at least one site created
Your Site ID (found in your Lynkow dashboard under Site Settings)
Installation
Install the Lynkow SDK from npm:
npm install lynkowOr with your preferred package manager:
# yarn
yarn add lynkow
# pnpm
pnpm add lynkowEnvironment Setup
Create a .env.local file in the root of your project and add your Site ID:
NEXT_PUBLIC_LYNKOW_SITE_ID=your-site-id-hereYou can find your Site ID in the Lynkow dashboard by navigating to Settings > General. It is a UUID that looks like a1b2c3d4-e5f6-7890-abcd-ef1234567890.
Create the SDK Client
Create a shared client instance that you will import throughout your application. This avoids re-initializing the client on every request.
Create the file lib/lynkow.ts:
import { createClient } from 'lynkow'
export const lynkow = createClient({
siteId: process.env.NEXT_PUBLIC_LYNKOW_SITE_ID!,
fetchOptions: {
next: { revalidate: 60 },
},
})Configuration options:
Option | Type | Default | Description |
|---|---|---|---|
|
| required | Your Lynkow Site ID |
|
|
| Default locale for all requests (e.g., |
|
|
| Options passed to every |
The SDK connects to https://api.lynkow.com by default. The revalidate: 60 setting tells Next.js to cache responses and revalidate them every 60 seconds via ISR. For near-instant updates, add a webhook endpoint (see Guide 11: Webhooks & Cache Revalidation).
First API Call: List Articles
Create a page that fetches and displays your published articles.
Create the file app/blog/page.tsx:
import { lynkow } from '@/lib/lynkow'
export default async function BlogPage() {
const { data: articles, meta } = await lynkow.contents.list({
limit: 10,
sort: 'published_at',
order: 'desc',
})
return (
<main style={{ maxWidth: '800px', margin: '0 auto', padding: '2rem' }}>
<h1>Blog</h1>
<p>{meta.total} articles published</p>
<ul style={{ listStyle: 'none', padding: 0 }}>
{articles.map((article) => (
<li key={article.id} style={{ marginBottom: '2rem' }}>
<a href={`/blog/${article.slug}`}>
<h2>{article.title}</h2>
</a>
{article.excerpt && <p>{article.excerpt}</p>}
<time dateTime={article.publishedAt}>
{new Date(article.publishedAt).toLocaleDateString()}
</time>
</li>
))}
</ul>
<p>
Page {meta.currentPage} of {meta.lastPage}
</p>
</main>
)
}The contents.list() method returns published articles with pagination metadata. Each article in the list includes its id, title, slug, path, excerpt, featuredImage, publishedAt, and locale -- but not the full body HTML, which keeps list responses fast.
Display a Single Article
Create a dynamic route to display a full article by its slug.
Create the file app/blog/[slug]/page.tsx:
import { lynkow } from '@/lib/lynkow'
import { notFound } from 'next/navigation'
type Params = Promise<{ slug: string }>
export default async function ArticlePage({ params }: { params: Params }) {
const { slug } = await params
let article
try {
article = await lynkow.contents.getBySlug(slug)
} catch {
notFound()
}
return (
<main style={{ maxWidth: '800px', margin: '0 auto', padding: '2rem' }}>
<article>
<h1>{article.title}</h1>
{article.author && (
<p>
By {article.author.fullName} ·{' '}
<time dateTime={article.publishedAt}>
{new Date(article.publishedAt).toLocaleDateString()}
</time>
</p>
)}
{article.featuredImage && (
<img
src={article.featuredImageVariants?.hero || article.featuredImage}
alt={article.title}
style={{ width: '100%', height: 'auto', borderRadius: '8px' }}
/>
)}
<div dangerouslySetInnerHTML={{ __html: article.body }} />
{article.categories.length > 0 && (
<div>
<strong>Categories:</strong>{' '}
{article.categories.map((cat) => cat.name).join(', ')}
</div>
)}
{article.tags.length > 0 && (
<div>
<strong>Tags:</strong>{' '}
{article.tags.map((tag) => tag.name).join(', ')}
</div>
)}
</article>
</main>
)
}The contents.getBySlug() method returns the full content object including the rendered HTML body, author, categories, tags, structuredData, and SEO fields like metaTitle and metaDescription.
Understanding the Response Types
ContentSummary (returned by contents.list())
Lightweight representation used in listing pages:
interface ContentSummary {
id: string
title: string
slug: string
path: string
excerpt: string | null
featuredImage: string | null
featuredImageVariants: Record<string, string> | null
publishedAt: string
locale: string
createdAt: string
}Content (returned by contents.getBySlug())
Full content with body and relationships:
interface Content {
id: string
title: string
slug: string
path: string
body: string // Rendered HTML
excerpt: string | null
featuredImage: string | null
featuredImageVariants: Record<string, string> | null
publishedAt: string
author: {
id: number
fullName: string
avatarUrl: string | null
} | null
categories: Array<{
id: string
name: string
slug: string
path: string
locale: string
}>
tags: Array<{
id: string
name: string
slug: string
locale: string
}>
structuredData: Record<string, unknown> | null
metaTitle: string | null
metaDescription: string | null
ogImage: string | null
createdAt: string
updatedAt: string
}PaginationMeta
Returned as meta in paginated responses:
interface PaginationMeta {
total: number
perPage: number
currentPage: number
lastPage: number
}Next Steps
You now have a working integration with Lynkow. Here is where to go from here:
Build a Complete Blog with Next.js -- Full blog implementation with categories, tags, pagination, SEO metadata, JSON-LD, and responsive images.
API Reference -- Complete documentation of all SDK methods and response types.
Media & Images -- Learn how to use
lynkow.media.srcset()andlynkow.media.transform()for responsive, optimized images.Localization -- Serve content in multiple languages with locale-aware queries.