Hey everyone!
I’m still working hard on Gland, and after a lot of refactoring and R&D, I’m excited to share some of the new developments. Gland is getting closer to its final syntax, and I’ve decided to make it fully event-driven (EDS-based), inspired by frameworks like NestJS and Angular.
It means:
- DI system: Similar to NestJS, for easy dependency injection.
- Controller, Import, Export: Just like NestJS, but with a twist—Channels replace traditional providers.
- Channels instead of Providers: Channels handle logic, making your app more modular and scalable.
- Pure and lightweight: Built from the ground up with minimal dependencies, no unnecessary packages—everything is kept lean and efficient.
Why EDS? (Event-Driven System)
Instead of returning data directly from controllers, everything in Gland is driven by events. This makes the app more modular, scalable, and flexible. Events trigger actions and responses, making the whole flow smoother and more intuitive.
Example:
@Controller('users')
class UserController {
@Get('/:id')
getUser(ctx: Context) {
const result = ctx.emit('read:server', ctx);
try {
throw Error('Hello world');
} catch (error) {
return ctx.emit('read:server:error', { error, result });
}
}
}
Here, ctx.emit('read:server', ctx)
sends an event called users:read:server
, and a Channel listens for it:
@Channel('users')
class UserChannel {
@On('read:server')
get(ctx: Context) {
return 10;
}
}
Now the entire data flow is event-driven
What’s Next?
Right now, Gland is still under development, and the ideas are evolving. The core concepts are being implemented, and I'm exploring new ways to make event-driven architecture more intuitive for web development.
Contribute or Share Your Ideas!
Gland is under active development, and the idea is still evolving. If you support the project, feel free to star it, open issues, submit pull requests, or share your ideas on GitHub. Whether you spot a bug or have a new feature in mind, your feedback is incredibly valuable.
I’d love to hear your thoughts—does this event-driven approach feel more flexible and modular compared to the traditional patterns? Or do you see potential challenges? Let’s start a conversation!
Top comments (39)
Do we really need another new web framework?
It really depends on what you’re looking for. Express still "works," and NestJS still "works," so if those fit your needs, there's no reason to switch.
But whether we need a new framework or not comes down to what problems you're trying to solve. Gland isn't trying to replace NestJS it’s taking a different, fully event-driven approach that makes code more modular and flexible. If that resonates with your project’s needs, then it’s worth considering. If not, sticking with what already works is totally fine.
This is the proper response. Even if it is the millionth JavaScript framework it is worth the attempt. At best it becomes something popular at worst you learned a lot about the problems that frameworks are trying to solve.
I agree. every new project is an opportunity to learn and grow, even if it's as simple as a basic calculator. For me, even if Gland doesn't become a huge success, the process of building it, the challenges I’ve faced, and the research I've conducted are incredibly valuable. Every experience, including failures, contributes to future successes as long as we learn from them.
This one is unique due to its event driven nature
Short answer? Yes. Even thousands more, as long people are creating them in the name of innovation.
Not sure I understand this. You're raising an event users.read.server assuming that some channel is implementing it, but the raiser has no type info to know what the channel will return. Am I supposed to do just project wide searches for strings to figure things out?
Good question! Right now, Gland’s event system is highly dynamic, allowing you to emit events without strict type constraints. While this provides flexibility, as you pointed out, it can make tracking responses harder.
One of the planned improvements is to introduce better type safety for emitted events, ensuring that the caller knows exactly what to expect. This could involve a type mapping system that links events to expected return types, making event-driven logic more predictable.
I’ll definitely take a closer look at this and explore ways to improve type inference in Gland’s event-driven flow. Thanks for the feedback!
In technology I see a recycling of ideas. One technology claims an improvement then comes another with its own baggages. I like the dynamics but the big question is why has not humanity succeeded in bringing a better technology we can all agree on? Is it even possible? What is wrong with us?
The problem is not with us, but with our idea of progress. Perhaps progress does not mean reaching a final and perfect technology at all, but rather the same constant movement between ideas, tests and failures.
I like @m_mdy_m response but here's another perspective. Maybe the problem is just that humans can't remain fixed on one thing. They say change is nature and we die the moment we stop changing and improving.
If all humanity agrees to use one perfect framework then that eliminates variety and subsequently, change. There has to be options.
Nice work, liked the idea, I would suggest to go beyond controllers and give more concrete implementation to leverage ore advanced patterns and architectures like domain driven design and clean architecture, I think as framework if u give some guideline and specific patterns to leverage those architectures with the use of events it will be very awesome
Also we need to think how can we build a package that uses events for db interactions and managing transactions
One last thing, we can use this pattern to add extra functionality for saving all interactions happen on the server through events, for example controller emits to service and service emits to db then emits back controller then to channel, we can add one extra functionality that records those events so it can be very useful for logs and traces
Thanks for the great insights! I really like the idea of going beyond just controllers and providing structured guidelines for architectures like DDD and Clean Architecture. That’s definitely something worth exploring—especially how event-driven patterns can naturally fit into these architectures and enhance modularity and maintainability.
I've already been working extensively on this idea and actively exploring ways to integrate these principles into Gland. Additionally, I plan to release third-party modules for database interactions that seamlessly integrate with Gland’s event-driven approach. These modules will provide a clean, decoupled way to manage data without tightly coupling the database logic to the application’s core.
In the future, I will also publish detailed documentation and guidelines on how to build third-party extensions for Gland, ensuring that developers can easily create plugins and integrations that align with its architecture. Of course, this will come after Gland reaches a stable release.
I also love the suggestion about event-based logging and tracing. Implementing a system that tracks and records all emitted events could be incredibly useful for debugging, monitoring, and even replaying events for auditing purposes. This is definitely something I’ll be looking into as Gland evolves.
Really appreciate the feedback! If you have any concrete ideas, specific use cases, or even suggestions on how you'd like to see these features implemented, feel free to share—I’d love to refine Gland’s event-driven approach even further.
Hey!
This is very interesting approach 👍 with event driven framework, I feel like writing state-machines in the backend would fit nicely.
I have a thought about the ctx.emit. I feel like it should not return result of the channel's event handler (10). Emitter usually should not know or care who handled the event and listeners should act on their own behalf.
Typically, if original emitter needs data, some listener would emit a response event, which the original emitter would be listening to.
Thank you for your thoughtful comment! You’ve raised a really important point about how event-driven systems should work, and I completely agree with the idea that emitters shouldn’t necessarily care about who handles the event or how it’s handled. This is actually one of the core principles behind Gland’s design, and I’d love to explain how we’ve approached this.
In Gland, ctx.emit is designed to give developers flexibility. While it can return the result of the handler, it doesn’t have to. This is intentional because we want to support both scenarios:
When you need a response: Sometimes, you might want to ensure that an event has been handled before moving forward. For example, if you’re processing a payment, you might want to confirm that the payment was logged before proceeding. In this case, waiting for a response from the handler makes sense.
When you don’t need a response: In other cases, like sending a notification, you might not care about the result at all. Here, you can simply emit the event and let the listeners handle it independently.
This flexibility allows developers to choose the right approach for their specific use case. If you prefer a more decoupled workflow where the emitter doesn’t wait for a response, you can design your system so that listeners emit follow-up events, and the emitter listens for those if needed. This keeps the emitter completely unaware of who’s handling the event or how it’s being handled, which aligns with your suggestion.
For example, imagine a scenario where a user signs up:
user:signup
event.user:created
event.user:created
event and sends a welcome email.In this case, the emitter doesn’t need to know about the database or the email service. It just broadcasts the event, and the listeners handle the rest.
That said, I completely understand your concern about the emitter potentially becoming too involved in the handling process. This is something I’ll keep in mind for future updates. For example, we could introduce stronger type constraints or event-response contracts to make it clearer when and how responses should be used. This would help developers avoid unintended coupling while still maintaining the flexibility that Gland offers.
Thanks again for sharing your thoughts! Your feedback is incredibly valuable, and it’s exactly this kind of discussion that helps make Gland better. If you have more ideas or suggestions, I’d love to hear them!
There are many cases where you may care that the event was handled before you moved on to something else, you may not care who has handled the event, but you many care that it has been handled.
Thank you for highlighting that nuance! I completely agree—there are indeed many cases where you might need confirmation that an event was handled before moving on, even if you don't care who handled it. In Gland, we've intentionally designed ctx.emit to be flexible. You can simply emit an event without waiting for a response when that's all you need, or you can structure your workflow so that follow-up events or asynchronous callbacks provide the confirmation you require.
For instance, in scenarios where processing order is critical (like logging a payment or updating a user record), you can have a listener emit a follow-up event to signal that the handling is complete. This allows you to wait for confirmation without coupling your emitter to a specific handler. It’s all about letting you choose the approach that best fits your use case.
Time to reset the clock
Gland is a new event-driven JavaScript web framework inspired by NestJS and Angular. It features dependency injection, controllers, and modular channels instead of providers, making apps more scalable and flexible. Using an Event-Driven System (EDS), actions are triggered by events rather than direct responses, enhancing modularity. The framework is lightweight, with minimal dependencies. Gland is still evolving, and feedback or contributions are welcome to refine its approach! 🚀
What we really need is a new web language.
Good, Keep going. I'm also making my own Framework for web still not have done that much. 😅
Great idea! I see a lot of potential for microservices here. Breaking the code into asynchronous, event-driven modules can make it non-blocking and much more efficient, which really helps with the performance across services.