Next.js Discord

Discord Forum

How increase speed of NextJS

Unanswered
California pilchard posted this in #help-forum
Open in Discord
Avatar
California pilchardOP
I have my app running but she is pretty slow and I dont know why. So I need help for best practice and maybe find the problematic part. I have this example :
https://medusa-b2c-starter-storefront.vercel.app/
Look how its fast for everything, I dont know why I dont have this.
So I just keep a basic page /app/[lang]/page.tsx :
export default function Home() {
    return (
        <div>HOME</div>
    )
}

And /app/[lang]/layout.tsx :
 export default async function Layout({
    children,
  }: RootLayoutProps) {
    return (
      <html suppressHydrationWarning>
        <body>
          {children}
        </body>
      </html>
    );
  }


And my middleware :
const intlMiddleware = createIntlMiddleware(routing);

// make a basic middleware just with intlMiddleware without Supabase auth middleware
export async function middleware(request: NextRequest) {
  return intlMiddleware(request);
}


Its fast but still slower than the example, but damn why I just have a empty page and I use next-intl, is it the problem ?

43 Replies

Avatar
Miniature Pinscher
Are you running the dev server or a production build?
Avatar
California pilchardOP
in dev but I know is slower on dev but even running the example one in dev is still way faster than my app
Like route through another page is instant
Avatar
Miniature Pinscher
Are you using turbopack for both?
Avatar
California pilchardOP
no turbopack
Avatar
Miniature Pinscher
That could be achieved with prefetching.
Avatar
California pilchardOP
But prefechting is done by default with Link no ?
There is an example (first is the example in production) and second my app (in production too). Wayy slower
Image
Image
Avatar
Miniature Pinscher
Yes, but only fully for static routes.
Avatar
California pilchardOP
But even the refresh time is way faster in the example, isnt only prefetching right ?
Avatar
Miniature Pinscher
Are you caching your fetches?
Avatar
California pilchardOP
the most queries are done client side with react-query soo
Avatar
Miniature Pinscher
Well, as I said. Add prefetch to all your Links if you want the site to be as snappy as possible.
That's one major difference between your site and the other one then.
Avatar
California pilchardOP
for example my movie page I do this, my layout.tsx :
export async function generateMetadata({
    params,
}: {
    params: {
      lang: string;
      film: string;
    };
}) {
    const { movie } = await getMovie(params.film, params.lang);
    if (!movie) return { title: 'Film introuvable' };
    return {
        title: movie.title,
        description: `This is the page of ${movie.title}`,
    };
}

export default async function MovieLayout({
    children,
    params,
}: {
    children: React.ReactNode;
    params: {
      lang: string;
      film: string;
    };
}) {
    const { id, movie } = await getMovie(params.film, params.lang);
    if (!movie) notFound();
    return (
        <>
            <MovieHeader movie={movie as any} />
            <div className="px-4 pb-4">
                <MovieNavbar movieId={id} />
                {children}
            </div>
        </>
    );
};

And page.tsx also have the getMovie() function :
export default async function MoviePage({
  params,
}: {
  params: {
    lang: string;
    film: string;
  };
}) {
    const { movie } = await getMovie(params.film, params.lang);
    if (!movie) notFound();
    return <MovieDescription movie={movie as any} />;
}

My query getMovie is supposed to be share with all 3 calls right ? Liike having only one call ?
export const getMovie = cache(async (id: string, lang: string) => {
    /// my function
})
Avatar
Miniature Pinscher
Yes.
Avatar
California pilchardOP
Mine should be faster for rendering first element so ? If I have some Skeleton for loading state
Avatar
Miniature Pinscher
Deduped.
Depends on if you leverage streaming.
Avatar
California pilchardOP
Of my leverage streaming ? What do u means by that ?
Also I use cache() but I dont really understand the difference with unstable_cache (but when using unstable_cache I have an error because my supabase client use cookies()
Avatar
Miniature Pinscher
You can move out the cookie accessing outside of the unstable_cache.
As an example:

export async function getSomeQuery() {
  const cookies = await cookies()
  const client = someClient(cookies)

  return unstable_cache(
    async () =>
      client.someQuery()
    [],
    {
      tags: [`query:${client.userId}`],
      revalidate: 60 * 60 * 24,
    },
  )();
}
Avatar
Miniature Pinscher
As opposed to unstable_cache, cache() is only for memoization of non-fetch functions, meaning it will only dedupe the request across the same render, not cache the data for subsequent requests.
Avatar
California pilchardOP
But do with unstable_cache the query is made once if the function is call from multiple element (page, generateMetadata, layout) ? Because doing this :
export const getMovie = (id: string, lang: string) => {
    const supabase = createServerClient();
    return unstable_cache(async () => {
        //getting data with supabase
        console.log('REQUEST MOVIE');
        return {
            id: movieId,
            movie,
        };
    }, [lang, 'movie', id], {
        revalidate: 60 * 60 * 24,
    })();
}

I have 3 console.logs, while with cache only one
Avatar
Miniature Pinscher
Well for one, you put the tags at the wrong place

export const getMovie = (id: string, lang: string) => {
  const supabase = createServerClient();
  return unstable_cache(
    async () => {
      //getting data with supabase
      console.log("REQUEST MOVIE");
      return {
        id: movieId,
        movie,
      };
    },
    [],
    {
      revalidate: 60 * 60 * 24,
      tags: [lang, "movie", id],
    },
  )();
};
Avatar
California pilchardOP
I have the same results :
    }, [], {
        revalidate: 60 * 60 * 24,
        tags: [lang, 'movie', id],
    })();

Also 3 console.log...
Even with static tag like ['movie']
Avatar
Miniature Pinscher
Make sure the function is marked as async
Avatar
California pilchardOP
Which one ? There is the entire function :
export const getMovie = async (id: string, lang: string) => {
    const supabase = createServerClient();
    return unstable_cache(async () => {
        const { id: movieId } = getIdFromSlug(id);
        const { data: movie, error } = await supabase
            .from('movie')
            .select(`
                *,
                cast:tmdb_movie_credits(
                    id,
                    person:person(*),
                    role:tmdb_movie_role(*)
                ),
                production_countries:tmdb_movie_country(
                    id,
                    country:tmdb_country(
                        *,
                        data:tmdb_country_translation(*)
                    )
                ),
                spoken_languages:tmdb_movie_language(
                    id,
                    language:tmdb_language(
                        *,
                        data:tmdb_language_translation(*)
                    )
                ),
                videos:tmdb_movie_videos(*)
            `)
            .match({
                'id': movieId,
                'cast.job': 'Actor',
                'production_countries.country.data.language': lang,
                'spoken_languages.language.data.language': lang,
                'videos.iso_639_1': lang
            })
            .maybeSingle();
        if (error) throw error;
        console.log('REQUEST MOVIE');
        return {
            id: movieId,
            movie,
        };
    }, [], {
        revalidate: 60 * 60 * 24,
        tags: [lang, 'movie', id],
    })();
}
And the page where she is called :
export async function generateMetadata({
    params,
}: {
    params: {
      lang: string;
      film: string;
    };
}) {
    const { movie } = await getMovie(params.film, params.lang);
    if (!movie) return { title: 'Film introuvable' };
    return {
        title: movie.title,
        description: `This is the page of ${movie.title}`,
    };
}

export default async function MovieLayout({
    children,
    params,
}: {
    children: React.ReactNode;
    params: {
      lang: string;
      film: string;
    };
}) {
    const { id, movie } = await getMovie(params.film, params.lang);
    if (!movie) notFound();
    return (
        <>
            <MovieHeader movie={movie as any} />
            <div className="px-4 pb-4">
                <MovieNavbar movieId={id} />
                {children}
            </div>
        </>
    );
};
Avatar
Miniature Pinscher
That looks correct at first glance. Are you sure you're importing the right getMovie function?
Avatar
California pilchardOP
sadly yes I only have one getMovie function in my code
even with this test one :
export const test = unstable_cache(async () => {
    await new Promise((resolve) => setTimeout(resolve, 1000));
    console.log('THIS IS A TEST');
    return 'test';
}, [], {
    revalidate: 60 * 60 * 24,
    tags: ['test'],
});
2 consoles logs
Avatar
Miniature Pinscher
I ran your exact code snippet and I'm only getting one console log.
Which Next version are you on?
Avatar
California pilchardOP
Next 14.2.16
thats crazy ahah
maybe there is something to enable for caching idk ?
Avatar
Miniature Pinscher
I might be wrong, but unstable_cache is only supported on > 15.0
Avatar
California pilchardOP
ohhh well I can try upgrade
Avatar
California pilchardOP
just updated to nextjs 15, same problem
Avatar
California pilchardOP
simple NextJS 15 page with that :
export async function generateMetadata(
    props: { params: Promise<{ lang: string; film: string; }> }
) {
    const dataTest = await test();
}

export default async function PageTest(
    props: {
        children: React.ReactNode;
        params: Promise<{
          lang: string;
          film: string;
        }>;
    }
) {
    const dataTest = await test();
    return (
        <div className='text-black'>
            test sef sef
        </div>
    )
};

I have no idea how u success make the test function console log once