#15 | Route Names & Type-Safe Route Generation - AdonisJS 7

Adocasts| 00:11:25|Mar 26, 2026
Chapters11
The chapter discusses moving away from hard-coded URL paths in redirects, forms, and links by introducing route naming to reference routes more reliably.

AdonisJS 7 makes route references type-safe by using names, not paths, and leverages a URL builder and a form component to cut hard-coded URLs from templates.

Summary

Adocasts’ walkthrough on AdonisJS 7 shows how naming routes with the as method unlocks type-safe URL generation across redirects, links, and forms. Kristian from Adocasts demonstrates how routes.ts can assign names like home and how AdonisJS derives default names from controller and method, reducing manual naming. The video highlights the routes.d.ts file generation, which ensures that any route reference in TypeScript matches defined routes and required parameters. Viewers see practical examples: redirecting to challenges.index by name, passing IDs for show pages, and using the URL builder for edit links. We also learn the URL builder’s parity with the two-route helper, including how it handles required route parameters. The episode showcases the benefits of decoupling URL paths from code, enabling effortless refactors (e.g., changing /challenges to /my-challenges) without touching every reference. Finally, Adocasts presents a form component that auto-generates action URLs, handles CSRF, and supports method spoofing for updates, simplifying create and edit pages in Edge templates.

Key Takeaways

  • Assign a name to routes with the as method in routes.ts (e.g., name home) to reference routes by name rather than by path.
  • AdonisJS 7 auto-generates default route names from the controller and method, expanding the named-route coverage beyond manually named routes.
  • Use the two-route helper to generate URLs by route name, providing optional parameters when needed (e.g., challenges.show requires an ID).
  • URL builder mirrors the two-route behavior and works inside controllers to produce links like challenges.edit with the correct ID parameter.
  • Changing a path (e.g., /challenges to /my-challenges) won’t require code changes everywhere because references rely on route names.
  • A form component can replace manual forms by taking a route name, params, and method, automatically handling CSRF and HTTP method spoofing for non-GET requests.

Who Is This For?

Essential viewing for AdonisJS 7 developers who want reliable, maintainable routing. It’s especially valuable for those implementing redirects, URL generation, and forms without hard-coded paths, ensuring type safety and easier refactors.

Notable Quotes

"So by giving this route definition the name home, we can now reference it by that name home instead of the actual slash path anytime we need to redirect or reference this particular route definition inside of our code."
Demonstrates the core benefit of naming routes for type-safe references.
"Adonisjs generates this file list using our defined routes and the required parameters as well."
Explains how routes.d.ts reinforces type safety by reflecting defined routes.
"That two route method accepts the name of the route as its first argument and then if needed it can accept the parameters as the second and additional options including query string values inside of those options as the third argument."
Shows how to use the route-building helper with parameters and options.
"By using the name for this route instead of the actual URL path of the route, we're saving ourselves the headache of having to search down all the usages of slashchallenges and updating it to slashmychallenges because the name is still going to remain the same."
Highlights long-term maintainability through stable route names.
"There is a form component here. It actually allows us to provide a route prop directly along with params and options and it will take those and build out a URL for us directly inside of this component and apply it into the forms attributes automatically for us."
Introduces a higher-level abstraction for forms that auto-manages URLs, CSRF, and method spoofing.

Questions This Video Answers

  • How do I create type-safe route references in AdonisJS 7?
  • What is the as method in AdonisJS routes and how does it affect URL generation?
  • Can I generate URLs by route name in AdonisJS 7 without hard-coding paths?
  • How does AdonisJS 7’s URL builder differ from the two-route helper?
  • What are the benefits of using the form component for AdonisJS 7 forms?
AdonisJS 7Route NamesType-Safe Route GenerationURL BuilderEdge.jsRouting in AdonisJSRoute ParametersForms with Route PropsCSRF AutomationHTTP Method Spoofing
Full Transcript
So far, we've been manually writing out the paths for our URLs inside of our redirects, forms, and links. Today, we're going to learn how we can do this even better by using names or identifiers for our routes instead of the actual hard-coded paths. So, we can give any of these routes within our routes.ts file an individual name using the as method on a per route definition basis. And the starter kit actually already gave us a route with a name manually defined as well for our homepage. So by giving this route definition the name home, we can now reference it by that name home instead of the actual slash path anytime we need to redirect or reference this particular route definition inside of our code. Why might we want to do this? Well, the first is type safety. Whenever we generate or refer to these routes within TypeScript, AdonisJS takes steps to ensure that we're using routes that are actually defined at the type level. If we check out the Adonisjs folder again, so if we scroll all the way up into our file tree, remember that this is where Adonjs places its autogenerated files and within here we'll find a routes.d.ts file nested within the server folder. Adonjs generates this file list using our defined routes and the required parameters as well. So within our routes.ts file, we only saw the homepage in particular having a name assigned to it. Yet all of these other routes that are defined within here already have a name as well as designated by the keys of the route definitions that we see within this file. We have a separated list of all of our route definition types. Those specific to get requests, head requests, post, and put. At this point, we don't have a delete defined. So delete is omitted from this list. The reason that all of these other routes already have a name despite us only specifying a manual name on our home route is due to a new behavior in Adon.js JS version 7 that will pluck out a default name for the route using the controller's name in conjunction with the method of the controller that's being used giving us the completed name of challenges.index for example for our/challenges path whenever we refer to routes using their names JS is going to use this file to ensure that that route actually exists within our route definitions in addition to ensuring that its parameter requirements are met as well. For example, our challenge show page requires an ID route parameter and that's noted here in this type. So, it's going to ensure whenever we reference this route anywhere that we're providing an ID parameter as well. So, thanks to this default controller naming behavior, we actually don't need to specify an individual name for each of these routes because they already have one via the default behaviors. Whenever it comes to actually referencing these routes, we can start with our challenges controller. This is going to allow us to see exactly what I'm referring to via this TypeScript feedback. So instead of doing redirect/challenges here within our response, we can instead omit our argument al together from the redirect and chain off of it an additional two route method off of that redirect. And whenever we enter into our string behavior, you'll notice that we get another one of these autocomplete lists, similar to filling out the method of our controller inside of our route definitions, offering up a list of all of the routes that we have defined so far inside of our application. Since we were redirecting to /challenges, we would want to point this to challenges.index, the name of that route that we were previously redirecting to. This two route method accepts the name of the route as its first argument and then if needed it can accept the parameters as the second and additional options including query string values inside of those options as the third argument. For our case our challenge index doesn't require any of those. So we can leave it as is right here. But if for example we wanted to instead redirect back to our challenges show page, you'll notice that this one does require a route parameter of our ID. And so we're going to get a red squiggly noting that we do need to specify a value for that ID route parameter. So if we add in a comma here, we're going to notice via our tool tip that the challenge show requires a params with an ID value right there as well. So we get a lot of type feedback with this. As soon as we add in our ID and we can just grab this directly off of our route parameters, everything goes back to being happy. Similar to our update, we can also go up to our store where we are also redirecting to /challenges and we can do the same thing. So we can get rid of that argument and add in a two route pointing it to our challenges index route. Now the other reason that we might want to use identifiers is because route patterns are actually prone to changing especially with the passage of time. So if for example we have a new requirement that we need to switch the URL of /challenges to slash my challenges. By using the name for this route instead of the actual URL path of the route, we're saving ourselves the headache of having to search down all the usages of slashchallenges and updating it to slashmychallenges because the name is still going to remain the same despite the URL change, meaning that challenges index will now automatically pick up and redirect to slashmy challenges instead of slashchallenges. So, it can save us that headache as well should we need to refactor in that sense. In addition to redirecting, we can also get references to URLs via the URL builder that Adonisjs provides and it behaves relatively similar to our two route as well. So within our show method inside of our challenges controller, we're plucking out the individual challenge and returning that back to the render states for the page. If inside of this controller, we also wanted to generate out the edit URL needed inside of this page to point to the edit page for the challenge, we could do that as well by using Adonjs's URL builder. So we can do edit URL equals and then access the URL builder by importing URL 4 from AdonJS core services URL builder. We can hit tab to autoimp import that from that path. And again this works similar to our redirect. So we just add in the route parameter name or identifier within the first argument. So we'll want challenges edit. We're going to get a squiggly because this does also require an ID route parameter for that challenge that we're editing. and we can grab that either via the params or our challenge ID. And you'll notice that since it's required, we'll get a type error if we try to use the challenge because challenge itself is going to be possibly undefined since we're using find from our array to try and find the actual challenge. So, if we're okay with that, we can use an exclamation point to assert that we're confident that we're going to find a challenge and TypeScript will then be happy. Or we can switch this to the one where we know it's going to be required via our route parameters. Then we'll pass that edit URL into our render state. And then finally, within our pages as show, I'm just going to commandclick into that to jump directly to that edge file. We can swap out the manually built URL right here with our edit URL, just like so. And with all that saved, if we jump back into our browser, we have our edit challenge button right here. If I hover over it, you can see down at the bottom lefthand corner that it is indeed pointing to the correct URL still. Fantastic. Going to go ahead and hit back there. jump back into our text editor because we don't need to necessarily build out the URL inside of our controller and pass it into our views to build out a URL. We can instead do that directly inside of Et.j.j.j.j.j.j.j.j.j.j.js as well using the route helper. So, if we jump into our index page here, instead of pointing to our create page via its hard-coded path, we can use double curly braces for our interpolation, access the route helper method off of our state. And again, this works the exact same as our URL 4. It's just since it's inside of Edge.js, JS. We're not going to necessarily get type notifications for it, but we can still point it to challenges.create to generate out a URL for the challenges.create route definition, which will still point us to /challenges/create. So, if we jump back into our browser, head back into our challenges index page, and hit create a new challenge, that's still going to take us to the create page as expected. Okay, one more spot to update that where we're still hard- coding the URL path. And that's within our components challenge grid item component. Again, we can go ahead and replace this hard-coded path with our route helper. Point it to challenges show. And then this one also requires an ID route parameter. So, we can do challenge ID to pass that in. AOK. Okay. Jumping back into our browser with that saved one more time, we should be able to click into any of our individual challenges and that should still work. AOK. Okay, fantastic. Finally, that leaves our forms. So, if we jump back into our create page here, we're still manually referencing a path within our forms action attribute. We could do the same thing that we did with our hrefs and do interpolation here with our route helper pointing this to challenges store and that would work a okay. But via our components from the starter kit that have been provided, we actually have a better option. There is a form component here. It actually allows us to provide a route prop directly along with params and options and it will take those and build out a URL for us directly inside of this component and apply it into the forms attributes automatically for us. In addition to this, we can also see that it's going to conditionally apply a CSRF field automatically for us if the method of the form submission is not a get request which again doesn't need the CSRF protection. So we can make use of this component to simplify things for ourselves. So let's jump back into our create page and I'll put this right above first and then we can get rid of our form al together. So we'll do at form to apply our component. We need to still apply our fields as the child content to this form. So we won't make it self-closing. And then we'll provide as props our routes name as challenges store. And then we also need to provide in the method of post as well to note that this should not be a get submission. Then where we're ending our form, we'll end our component. And now we can get rid of our form element al together because the form component will do that automatically for us. And it will also take care of our CSR ref field for us as well. So we can get rid of that too. So let's go ahead and give that a save. Jump back into our browser one more time. This was our create page that we added this to. So we'll create a new one real quick. So we can just call this form component. Give it 50 points. Hit enter to submit. And sure enough, there it is right there. Submitting still perfectly fine. We can do this as well for our edit page where the URL for our action is a little bit more complex because again we're using that HTTP method spoofing to switch on the server side our post request to a put whenever it matches against our route definitions. So again, let's go ahead and start by adding in our form component. And then we'll jump down to where we're ending this and add in our end designation. Inside of our props, we'll add in our route and provide its name of challenges.update. We need to also provide in the route params which go in as a separate prop and are designated as an object to state that the ID that we're updating is our challenge ID. And one super nice thing that this form component actually does is it will handle our HTTP method spoofing automatically for us. So we don't need to specify options with a query string. switching this to a put. Instead, we can just directly provide a method of put and it will read that and apply the method spoofing automatically for us, making things just that much simpler. So, we can now get rid of our form and our CSRF field and the end form element. And let's go try and edit our form component real quick. So, let's go into edit challenge form component 2. Hit enter to update it. And sure enough, that works perfectly fine as

Get daily recaps from
Adocasts

AI-powered summaries delivered to your inbox. Save hours every week while staying fully informed.