You downloaded a great Lottie animation, installed the react-lottie library, and now your Next.js build fails with a document is not defined error. Classic. The problem? The react-lottie library has not been maintained since 2020 and does not support Next.js Server-Side Rendering. The solution exists and it is simple: lottie-react.
Install the Right Library: React-Lottie
The first step is to install the right library. Forget react-lottie, use lottie-react instead:
npm install lottie-reactNext, place your animation JSON files in the public folder of your Next.js project. By convention, create a dedicated subfolder:
public/
└── animations/
└── loading.json
└── success.jsonIf you are working in TypeScript, create a types file for your Lottie components. In your types folder (or src/types), add:
// types/index.ts
export interface LottieProps {
jsonData: object;
loop?: boolean;
className?: string;
}These types will give you autocompletion and TypeScript validation on your components.
The Solution: Loading the Animation on the Client Side
Here is where most developers go wrong. If you use lottie-react directly in a Next.js Server Component, you will get the dreaded error:
ReferenceError: document is not definedWhy? Because lottie-react depends on lottie-web, which attempts to access the DOM during server-side rendering. Next.js 13+ uses Server Components by default, and the DOM does not exist on the server.
The elegant solution is to split your Lottie component into two separate files: a wrapper that handles dynamic loading, and a client component that does the actual rendering.
The Two-File Pattern
First, create the client component that uses lottie-react:
// components/animations/LottieClient.tsx
'use client'
import { LottieProps } from '@/types';
import { useLottie } from 'lottie-react';
const LottieClient = ({
loop = true,
jsonData,
className = "w-full",
}: LottieProps) => {
const defaultOptions = {
animationData: jsonData,
loop: loop,
};
const { View } = useLottie(defaultOptions);
return (
<div className={className}>{View}</div>
);
}
export default LottieClient;This component is marked 'use client' on the first line. It contains all the Lottie-related logic and can access the DOM without any issues.
Next, create the wrapper that uses Next.js's dynamic import:
// components/animations/LottieAnimation.tsx
'use client'
import { LottieProps } from '@/types';
import dynamic from 'next/dynamic';
import { ComponentType } from 'react';
const LottieWrapper: ComponentType<LottieProps> = dynamic(
() => import('@/components/animations/LottieClient'),
{ ssr: false }
);
const LottieAnimation = (props: LottieProps) => {
return <LottieWrapper {...props} />;
}
export default LottieAnimation;The { ssr: false } parameter is crucial: it tells Next.js to only load this component on the client side, after hydration. During server rendering, Next.js completely ignores this component.
Why It Works
This pattern solves three problems simultaneously:
SSR: The dynamic import with ssr: false prevents Lottie code from executing on the server.
Tree-shaking: The lottie-react library (and its ~82kb minified weight) is only downloaded if the component is actually used on the page.
Maintainability: You always import LottieAnimation, never LottieClient directly. This ensures that no one on your team accidentally uses the component without the protection wrapper.
Using It in Your App
Now that the architecture is in place, using your animations becomes effortless. Import your LottieAnimation component and pass it your animation JSON.
Basic Import and Usage
// app/page.tsx
import LottieAnimation from '@/components/animations/LottieAnimation';
import loadingAnimation from '@/public/animations/loading.json';
export default function Home() {
return (
<div className="flex justify-center items-center min-h-screen">
<LottieAnimation
jsonData={loadingAnimation}
loop={true}
className="w-64"
/>
</div>
);
}The JSON is imported directly as a JavaScript object. Next.js automatically handles the import of .json files without any additional configuration.
Your LottieAnimation component accepts three essential props:
jsonData (required): Your animation's JSON object. Import it from your public/animations/ folder.
loop (optional, default: true): Determines whether the animation should loop indefinitely. Pass false for an animation that plays only once.
className (optional, default: "w-full"): Tailwind or CSS classes to control the size and style of the container.
Usage stays simple and predictable. You control the size via CSS classes, the behavior via the loop prop, and conditional rendering with standard React patterns.
Pro Tips
A few common errors and classic pitfalls:
Error: "Module not found: Can't resolve 'lottie-react'"
You probably installed react-lottie instead of lottie-react. Uninstall and reinstall the correct version:
npm uninstall react-lottie
npm install lottie-reactError: "document is not defined"
You are using lottie-react directly without the dynamic wrapper. Make sure you import LottieAnimation and not LottieClient.
The animation is not displaying
Check that your JSON file is a valid Lottie export. Test it first on LottieFiles↗ to confirm it works.
The animation is choppy
The JSON is probably too heavy. Reduce the number of keyframes or simplify the shapes in After Effects.
Conclusion
Integrating Lottie animations in Next.js is not complicated when you use the right tools. In summary: install lottie-react, create your two components with the dynamic import pattern, and use them everywhere in your app without worrying about SSR.
This approach works equally well with Next.js 13, 14, or 15, and with both the App Router and the Pages Router. Lottie animations bring real added value to the user experience, and now you know how to implement them properly.
Give it a try.
Are you developing a web application or business software and need technical support? Discover our web and software development services or contact us to discuss your project.




