Deep Linking in Single-Page Applications
Learn how to create deep links in single-page applications that preserve state, handle query parameters, and work correctly with both hash and history-based routing.
Detailed Explanation
Deep Linking in SPAs
Deep linking means creating URLs that point to a specific view or state within a single-page application, allowing users to bookmark, share, and directly access any screen — not just the home page.
The Challenge
In a traditional multi-page website, each URL maps to a server-rendered HTML page. In an SPA, only one HTML page exists, and JavaScript handles all view transitions. The challenge is making URLs work as expected despite everything happening on the client.
State in the URL
A well-designed SPA encodes meaningful state in the URL:
https://app.example.com/projects/42/tasks?status=open&sort=due_date#task-789
\_____________________________/ \_/ \___/ \_________________________________/
base proj view filters & anchor
Components of deep link state:
- Path segments — resource identifiers (
/projects/42/tasks) - Query parameters — filters, sorting, pagination (
?status=open) - Hash fragment — scroll position or sub-section (
#task-789)
Implementation Patterns
React Router:
// Route definition
<Route path="/projects/:projectId/tasks" element={<TaskList />} />
// Reading params
const { projectId } = useParams();
const [searchParams] = useSearchParams();
const status = searchParams.get("status");
Next.js:
// app/projects/[id]/tasks/page.tsx
export default function TasksPage({ params, searchParams }) {
const projectId = params.id;
const status = searchParams.status;
}
Preserving State on Navigation
Best practices for deep links:
- Sync URL with state — every meaningful state change should update the URL
- Initialize from URL — when the page loads, read state from the URL first
- Use
replaceStatefor transient changes (like scroll position) - Use
pushStatefor navigation changes (like page transitions)
Common Pitfalls
- Lost state on refresh — if state is only in memory, refreshing loses it
- Broken back button — pushing too many history entries makes the back button feel broken
- Stale links — deep links to deleted resources need graceful 404 handling
- Missing server fallback — the server must return the SPA shell for all routes (not 404)
Use Case
Deep linking is essential for any SPA that needs to support shared URLs, browser history, and search engine indexing. Applications like project management tools, dashboards, and e-commerce sites rely on deep links to let users share specific views with teammates or bookmark filtered results for later.