Next.js Discord

Discord Forum

Move to Next.js?

Unanswered
Dwarf Crocodile posted this in #help-forum
Open in Discord
Dwarf CrocodileOP
I am new to webD. I am currently using CRA, flask and sqlite DB. Hosted on AWS (ec2) with nginx server to serve my Frontend and proxy my requests to flask.

i have few questions:
- Can I move my current setup to Nextjs without changing my deployment steps?
- Advantages and disadvantages (if any) over the current setup?

100 Replies

Well the big advantage is CRA is end of life and nextjs isnt!
is that why CRA was deprecated
xD
@Dwarf Crocodile is that why CRA was deprecated
Yeah it isn’t maintained any more! Your options are either NextJS or React+Vite! The latter is still great for your fully client side apps. Whereas if you want SEO benefits, speed etc for a website rather than a web app! NextJS is the way! NextJS can also do web apps too!
Dwarf CrocodileOP
Yes I need SEO benefits too
i hadto use react helmet and mimic SSR somehow on my current CRA setup
:/
Yeah NextJS is all built in! And you still run it behind nginx!
Dwarf CrocodileOP
so i dont have to do much deployment changes?
just migrate to next?
what about my flask APIs, (doing some user management stuff there)
Just call them from next
Dwarf CrocodileOP
will it support everything? that i am using on flask?
or for the time being can I keep my flask APIs ?
You could rewrite the backend in next if you wanted! But I’ll be honest I always use Django as my backend as I prefer Python for that stuff and you can call any api you want in nextjs
Dwarf CrocodileOP
yes, i prefer flask, so i am thinking if I move, i will keep my flask backend (for the time being)
You don’t need to make a backend change to use Next.js, Next comes with nice β€œbackend integration” but it’s not mandatory, I would say it’s even better to keep them separated in bigger projects
Dwarf CrocodileOP
and are there any good code repo's that i can have a look at?
which has like marketing pages (home, demo, technology) + then some login page and then some protected routes for user dashaboard?
cauz mine is similar to that
just to get idea
how things would look like
https://github.com/adb-software-solutions/debuglife

I’m working on this at the moment. NextJS, Django backend. Mainly been doing client side stuff so far but feel free to take a look
I’ve only got dashboard stuff so far!
Dwarf CrocodileOP
thanks, i will have a look πŸ‘
if you have any other code examples, plz do share, kind of new to these things
I’ll see if I have any other public repo when I get to my PC!
Dwarf CrocodileOP
Hey, should I migrate my current CRA directly (which also has many unused dependencies in it, that i will need to remove)
or
Should I start with a new Nextjs project and simply copy-paste my CRA react components in it?
Start from scratch, copy and update the components you need.
Dwarf CrocodileOP
Ok
and which one should I go for: app router or page router?
this is how it looks right now:

CRA
│── public/                
│── src/
β”‚   β”œβ”€β”€ dashboard/    # admin-dashboard related components & pages
β”‚   β”œβ”€β”€ marketing/    # Marketing related components & pages (Home, features, pricing)
β”‚   β”œβ”€β”€ utils/            
β”‚   β”œβ”€β”€ App.js             
β”‚   β”œβ”€β”€ index.js           
β”‚   β”œβ”€β”€ index.css           
│── .env
│── .gitignore           
│── README.md              
│── package.json            
│── tailwind.config.js     
app router, its the go-to going forward.
Dwarf CrocodileOP
Hey guys, still confused about how to do folder structuring with app router. Saw couple of videos on app router too, got to know about grouping, which I think will be helpful.


But I have 2 extra pages that I want to show only to admins and not to clients.
Also, when role == admin, I want the dashboard route to be /dashboard/admin-viewer and for clients it will be /dashboard/viewer.

the current CRA strucutre:
CRA
│── public/                
│── src/
β”‚       β”œβ”€β”€ marketing/    ( # Public-facing pages)
β”‚       β”‚       β”œβ”€β”€ components/
β”‚       β”‚       β”‚    β”œβ”€β”€ Cta.jsx
β”‚       β”‚       β”‚    β”œβ”€β”€ Footer.jsx
β”‚       β”‚       β”‚    β”œβ”€β”€ Navbar.jsx
β”‚       β”‚       β”‚
β”‚       β”‚       β”œβ”€β”€ pages/
β”‚       β”‚             β”œβ”€β”€ Homepage.jsx
β”‚       β”‚             β”œβ”€β”€ Features.jsx
β”‚       β”‚             β”œβ”€β”€ Pricing.jsx
β”‚       β”‚             β”œβ”€β”€ Contact.jsx
β”‚       β”‚             β”œβ”€β”€ PrivacyPolicy.jsx
β”‚       β”‚             β”œβ”€β”€ TermsOfUse.jsx
β”‚       β”‚
β”‚       β”œβ”€β”€ dashboard/   ( # Protected dashboard section)
β”‚       β”‚       β”œβ”€β”€ components/
β”‚       β”‚       β”‚     β”œβ”€β”€ AdminDashboard.jsx
β”‚       β”‚       β”‚     β”œβ”€β”€ ClientDashboard.jsx
β”‚       β”‚       β”‚     β”œβ”€β”€ AdminViewer.jsx
β”‚       β”‚       β”‚     β”œβ”€β”€ ClientViewer.jsx
β”‚       β”‚       β”‚     β”œβ”€β”€ AddClient.jsx
β”‚       β”‚       β”‚     β”œβ”€β”€ few more.....
β”‚       β”‚       β”œβ”€β”€ pages/
β”‚       β”‚             β”œβ”€β”€ Dashboard.jsx (render dashboard based on roles: admin, client)
β”‚       β”‚             β”œβ”€β”€ Viewer.jsx
β”‚       β”‚             β”œβ”€β”€ PasswordReset.jsx
β”‚       β”‚             β”œβ”€β”€ (2 more pages if role == admin)
β”‚       β”‚
β”‚       β”œβ”€β”€ utils/            
β”‚       β”œβ”€β”€ App.js             
β”‚       β”œβ”€β”€ index.js           
β”‚       β”œβ”€β”€ index.css           
│── .env
│── .gitignore           
│── README.md              
│── package.json            
│── tailwind.config.js
Roseate Spoonbill
I think you need to clarify the URL structure you want to achieve. There are multiple ways to do something that resembles what you described and it's hard to tell which will match your use case without knowing details.

Off the top of my head, these are related mechanisms you can work with (in random order):
- Redirects and rewrites - e.g. upon login redirect to home page based on user role.
- Middleware - run code before entering any route and decide if user should be redirected etc - be careful though, this runs on every route in the whole app
- Nested layouts - run authentication checks in layout within folder. Redirect if needed, or show 404 page.
Dwarf CrocodileOP
Like, in CRA I used to do like this in my app.js:

{isLoggedIn && (
  <Sidebar handleLogout={handleLogout}>
        <Routes>
          <Route
            path="/login"
            element={
              roleValue === "admin" ? (
                <Navigate to="/admin-viewer" />
              ) : (
                <Navigate to="/viewer" />
              )
            }
          />
          <Route path="/admin-viewer" element={<AdminViewer />} />
          <Route
            path="/viewer"
            element={
              roleValue === "client" ? (
                <ClientViewer />
              ) : roleValue === "employee" ? (
                <EmployeeViewer />
              ) : (
                <div>Unauthorized</div>
              )
            }
          />
          <Route path="/dashboard" element={<Dashboard />} />
          <Route path="/job-submit" element={<JobSubmit />} />
          <Route path="/job-status" element={<JobStatus />} />
          <Route path="/change-password" element={<ChangePassword />} />
          <Route path="*" element={<NotFound />} />
        </Routes>
      </Sidebar>
)}

I was using isLoggedIn to check if a user is logged-in and roleValue to redirect users from /login to respective paths:
- if admin, then /admin-viewer which opens <AdminViewer/>
- if client, then /viewer which opens <ClientViewer/>
- if employee, then /viewer which opens <EmployeeViewer/>
Dwarf CrocodileOP
don't know if this will help
Roseate Spoonbill
So out of what I mentioned, I'd probably do one of the following:
- create (dashboard)/dashboard/(admin-only)/ directory and put a new layout inside. On the top of the layout, you can authenticate the user and perform something like if (!user.isAdmin) return notFound(). You can also do it in your current structure, by putting this check in your admin-only pages.
- use [middleware](https://nextjs.org/docs/app/building-your-application/routing/middleware) to have all auth checks done in one place - there's bunch of examples for this, e.g. https://medium.com/@turingvang/nextjs-middleware-auth-56a2da4ea341

Layout/page level auth is more page-oriented. It will also make it easier to run only for pages that need actual auth.
Middleware method is more if you need fine-tuned response codes, or simply want to have all declared in one place. Downside is that middleware will run on all routes (including internal next routes and api handlers), so you need to be extra careful what is middleware configured to run with.
I use an Auth Guard added to my layout.
@adam.birds I use an Auth Guard added to my layout.
About that, if you delete the cookies manually and then navigate via Links in your app (within the same layout), do you get redirected because you’re not authenticated or keeps navigating ?

Since session is attached to Layout via a wrapper (AuthGuard) and layouts are maintained in navigations, what happens?
Also, I thought I could only use a node-based server in Nextjs, but it also allow flask servers?
https://vercel.com/templates/next.js/nextjs-flask-starter

Does this mean, i can simply copy paste my backend APIs into Next's /api ?
@Dwarf Crocodile https://vercel.com/templates/next.js/nextjs-flask-starter Does this mean, i can simply copy paste my backend APIs into Next's /api ?
Roseate Spoonbill
If you are trying to get comfortable with Next, try to use it solo first. Next is JS-based and running it with flask will essentially run python and next in parallel. Not that it's a bad thing, but not necessarily where Next will shine. With Next you have the ability to call server functions from client-side code, which not only is type-safe, but also allows you to reduce number of API route handlers to bare minimum required by external clients.

Once you get comfortable with Next and learn the pros and cons of the solution, as well as how revalidation patterns work, then you'll be able to make more educated decision about incorporating other languages/frameworks into the stack.

Ofc. that is simply my subjective opinion, do whatever feels right for your learning path πŸ˜‰
Roseate Spoonbill
Don't forget to mark the topic as solved once you are happy with the response πŸ˜‰ It helps a lot in keeping the forum clean!
Dwarf CrocodileOP
I might have few more doubts, so keeping it open for a day or two. πŸ™‚
Roseate Spoonbill
You should not make those checks client side - make sure the layout, or the page that preforms it are server-side. They wouldn't see a glimps of a page, but it's still a security risk to do any authentication on client. So if you need client side in those pages, wrap them in dedicated parent components and render them in the laout/page that runs on server.
Next will put client-side code in there only if you ask it to do so. All pages by default are server-side unless you tell them to be client side.
Dwarf CrocodileOP
can i perform those checks in layout.jsx or page.jsx any one? (if both are server-side)
or do i need to perform checks in subsequent sub-folders aswell?
Roseate Spoonbill
@Dwarf Crocodile It's not determined by file structure. For all I know all those pages may be client side or server side. As I said - pages and layouts are by default server-side. Only when you write use client at the top, your DOM tree will have client-side code from that point downward (it's a bit oversimplification from my side, but that's mostly the case anyway). If you have async put in front of your component/page/layout then it is almost certainly server side (at least in current versions of Next). You can ensure that by using server-only module. Once imported e.g. in the auth file, or on the page itself, it will throw an error if you try to import it on client: https://nextjs.org/docs/app/building-your-application/rendering/composition-patterns#keeping-server-only-code-out-of-the-client-environment
Dwarf CrocodileOP
This is my ProtectedRoute.jsx component: https://codefile.io/f/QUM3gUI6mC

And i was thinking to do this in my admin's layout.tsx:

import "../../globals.css";
import Sidebar from "../../../components/dashbaord/sidebar";
import { Inter } from "next/font/google";

const inter = Inter({ subsets: ["latin"] });

export default function DashboardLayout({ children }) {
  return (
    <html lang="en" className={inter.className}>
      <body>
        <ProtectedRoute allowedRoles={["admin"]}>
          <div className="flex flex-row">
            <Sidebar />
            <div className="flex-grow">{children}</div>
          </div>
        </ProtectedRoute>
      </body>
    </html>
  );
}
Roseate Spoonbill
Add import "server-only" at the top, and you'll be 100% sure that this is the server-side code πŸ˜‰
Dwarf CrocodileOP
by default aren;'t they server-side?
Roseate Spoonbill
Yes, they are. But if you make a mistake and try to render them in client-component later on, this will ensure to throw an error at you before you make that change go public.
So call that being extra safe πŸ˜‰
Roseate Spoonbill
Yes. The server-side code will check auth etc. and once it passes, only then it will return client components to the user.
Dwarf CrocodileOP
if someone does: /admin/change-password/ directly, still it will perform that check and throw an error right? cauz I am performing it in layout.jsx and all the rest pages are children of this layout.jsx
Roseate Spoonbill
Yes. Layout runs first, before any of the pages inside.
@Roseate Spoonbill Yes. The server-side code will check auth etc. and once it passes, only then it will return client components to the user.
Dwarf CrocodileOP
also, i am storing role and jwt-token in localStorage, how can server read those local values?
and to use middleware i think I need to put those in a http cookie instead of savign them in local?
Roseate Spoonbill
Well, it cannot. You must find other ways to pass that info to server. Cookie is probably the easiest.
@Roseate Spoonbill Yes. The server-side code will check auth etc. and once it passes, only then it will return client components to the user.
Dwarf CrocodileOP
hey. my layout.jsx is server side.

But the imported component ProtectedRoute.jsx is client-side.

Is it okay?
Roseate Spoonbill
You do need server-side check as well. You cannot rely on client-side checks only. I'd put auth info in cookies and check those. Even if the cookie simply carries the JWT token.
Think of it that way: client-side auth code are helpers at best - show error messages when you are logged out, redirect after token invalidates and so on. Server-side code must do the check if you want to be safe.
Otherwise you risk exposing stuff.
Do not trust that having your auth check in your Layout makes your pages protected.

Layout.tsx isn’t a good place to do auth checks
Dwarf CrocodileOP
:/
Roseate Spoonbill
Yeah, just wanted to write this - I just found some info about layouts being leaky when sent specific header. I cannot find any details or reports on next repo, so you may need to switch to Page-level check or to middlewares.
The docs say it’s not a Guarantee that Layouts are rendered before the page is rendered, yes they’re nested visually when they reach the client but it’s not a guarantee when they’re rendering

Also, Layouts maintain state and don’t re-render on navigations so if you make the check it’ll only be made once for the first page rendering inside the layout
Make checks on the page level by abstracting an utility funcion and using it on every protected page at the very top of the page component (have in mind this will turn your page Dynamic if it wasn’t already, since you’re accessing dynamic APIs like cookies and headers), and for static pages the only way is doing it through middleware.
Roseate Spoonbill
Definitely do not rely on client-side checks only - if your ProtectedRoute is the only place you verify the session, it's not enough.
Dwarf CrocodileOP
i am not using cookies right now. is there any way i can do server-side checks without storing my roles and jwt token to cookies?
Roseate Spoonbill
Cookies are the easiest way TBH. Simply set a http-only cookie upon login.
@Dwarf Crocodile but If the 1st check was passed (meaning he was with an admin role), then its good right? he can then access other admin-pages as well
Yes but if the session finishes either because it was timed out or you deleted cookies manually you’ll still have access to it
Dwarf CrocodileOP
Also, inside my flask backend APIs, i am doing a role-check, if its admin, only then he can get details of clients, employees. otherwise i am returning a 403 unauthorized message
Either way doing auth checks in Layouts is not recommended, even the Next.js team discourages that practice
@Roseate Spoonbill Cookies are the easiest way TBH. Simply set a http-only cookie upon login.
Dwarf CrocodileOP
hmm..i will look in to. i was currently setting them in localstorage upon login
Roseate Spoonbill
You can do this if your data sources are always through API and by sending the token. But if next needs to be able to verify this, it must get this in the request - hence the cookies.
and cheking if role matches
Roseate Spoonbill
Ok, let me sum it up for you as this is a bit long for how the context of the conversation grows:
- Out of the auth options I presented, the layout one is not good, so disregard this and forget I ever mentioned it, as I learned today. I'm sorry for mentioning this without proper check - that's my bad.
- Put auth checks on Page level, but only if page is server-side.
- Middleware checks are fine too if you start using cookies
- You can skip the auth check if you only get protected data through external API - in this case you still need to handle auth errors, but client-side is fine for this.
- Server-side checks require you to use cookies as localStorage is not available to server
- Treat your ProtectedRoute code as UX feature - anyone can set localStorage to anything, so without server-check it's only something to put user in the right place, not something that will protect your data.
Dwarf CrocodileOP
okay, cool πŸ‘
I just changed my role from client to admin. So I was able to see the admin dashboard UI. But since my jwt token still has client role in it (when it was signed on server at the time of login), I am unable to perform anything and see anything.
i am considering this not-bad. But this can be improved by using cookies and middlewares. Then users wont be able to access those unauthorized routes.
Roseate Spoonbill
Sounds like you got it right.