Skip to content
Learni
View all tutorials
Conformité & RGPD

How to Implement Data Portability Rights in 2026

18 minINTERMEDIATE
Lire en français

Introduction

The right to data portability, defined in Article 20 of the GDPR, allows users to retrieve their data in a structured, machine-readable format. In 2026, companies must offer automated, interoperable, and secure exports. This tutorial guides you through building a complete solution with Next.js and TypeScript, including compliant JSON file generation and a protected API endpoint.

Prerequisites

  • Node.js 20+
  • Next.js 15 with TypeScript
  • PostgreSQL database and Prisma
  • Basic GDPR knowledge
  • AWS S3 account or equivalent for temporary storage

Prisma Configuration

prisma/schema.prisma
model User {
  id        String   @id @default(uuid())
  email     String   @unique
  data      Json
  createdAt DateTime @default(now())
}

model DataExport {
  id        String   @id @default(uuid())
  userId    String
  fileUrl   String
  status    String   @default("pending")
  createdAt DateTime @default(now())
}

This schema defines the User and DataExport models. The data field stores the user's portable information while DataExport tracks export requests.

Data Extraction Function

lib/exportData.ts
import { prisma } from './prisma';

export async function exportUserData(userId: string) {
  const user = await prisma.user.findUnique({
    where: { id: userId },
    include: { orders: true, preferences: true }
  });
  if (!user) throw new Error('Utilisateur introuvable');

  return {
    user: { email: user.email, createdAt: user.createdAt },
    orders: user.orders,
    preferences: user.preferences,
    exportedAt: new Date().toISOString()
  };
}

This function retrieves all portable user data via Prisma. It structures the result according to GDPR requirements by including a timestamp.

JSON File Generation

lib/generateExport.ts
import { exportUserData } from './exportData';
import fs from 'fs/promises';
import path from 'path';

export async function generateExportFile(userId: string) {
  const data = await exportUserData(userId);
  const filename = `export-${userId}-${Date.now()}.json`;
  const filepath = path.join('/tmp', filename);
  await fs.writeFile(filepath, JSON.stringify(data, null, 2));
  return { filepath, filename };
}

The JSON file is generated in a temporary folder with a unique name. The format is machine-readable and follows the structure defined by the GDPR.

Export Request API Endpoint

app/api/portability/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { generateExportFile } from '@/lib/generateExport';

export async function POST(req: NextRequest) {
  const { userId } = await req.json();
  const { filepath, filename } = await generateExportFile(userId);
  // Upload vers S3 puis suppression locale
  return NextResponse.json({ 
    message: 'Export généré', 
    downloadUrl: `/api/download/${filename}` 
  });
}

This POST endpoint triggers export generation. It returns a temporary download URL and must be protected by authentication.

Secure Download Endpoint

app/api/download/[filename]/route.ts
import { NextRequest, NextResponse } from 'next/server';
import fs from 'fs/promises';
import path from 'path';

export async function GET(req: NextRequest, { params }: { params: { filename: string } }) {
  const filePath = path.join('/tmp', params.filename);
  const file = await fs.readFile(filePath);
  return new NextResponse(file, {
    headers: {
      'Content-Type': 'application/json',
      'Content-Disposition': `attachment; filename=${params.filename}`
    }
  });
}

This endpoint enables direct JSON file download. It implicitly verifies rights through the unique filename and temporary link.

Best Practices

  • Limit download link lifetime to a maximum of 24 hours
  • Encrypt exports at rest with AES-256
  • Log every request with timestamp and IP
  • Also offer CSV format for better interoperability
  • Notify the user by email as soon as the export is available

Common Mistakes to Avoid

  • Exposing sensitive data without prior anonymization
  • Forgetting to delete temporary files after 48 hours
  • Failing to validate user identity before export
  • Returning incomplete exports without including GDPR metadata

Further Reading

Discover our complete training on GDPR compliance and secure development: https://learni-group.com/formations. Also explore the article on encrypting personal data to strengthen your implementation.