Show HN: Cot: a Rust web framework for lazy developers

68 pointsposted 6 hours ago
by m4tx

71 Comments

ldng

42 minutes ago

I would love a Django clone in Rust that does NOT do async. Dead simple to debug instead of performance oriented.

m4tx

16 minutes ago

That's actually a very good point. I was thinking a lot about whether to make async a requirement. Given that sync code is often easier to reason about and debug and Cot tries to be developer-friendly, I'm leaning towards "sync by default, async when you need to", but I'll need to explore this more. Thanks for this thought!

ygouzerh

20 minutes ago

I just had an issue yesterday in my company where a backend keeps crashing, because a function blocking the main thread, which means that the healthcheck endpoint was not responding... Async is definitely a needs

brink

31 minutes ago

No threading either. Just a single thread serving one client at a time.

pseudocomposer

5 hours ago

The post mentions an ORM, but the docs don’t provide any examples of how it works. How does the Cot ORM compare to Diesel? There are certainly places where I find Diesel falls short of, say, ActiveRecord (like traversing relationships via “includes”/“eager_load”/etc.). I’m not convinced that these shortcomings warrant a separate ORM as opposed to making contributions to Diesel, but I’m open to being wrong. Are there any particular shortcomings that motivated starting from scratch? One thing I really like about Rust dev is the way ORM and API server concerns are separated. Will Cot’s server support using Diesel? Can it be used without the ORM package being involved at all?

m4tx

5 hours ago

About the docs, there is a guide chapter dedicated to the ORM: https://cot.rs/guide/latest/db-models/

There are several reasons I don't like the existing ORMs in Rust, many of them being overly verbose, some generating unnecessary files, and having somewhat weird DSLs being the main reasons. The main reason, I think, was that none of them supports automatically generated migrations, and I absolutely loved that feature in Django. The differences between existing ORMs sound like a neat idea for another blog post, to be honest, so I'll probably do that soon!

Diesel absolutely can be used, there is no reason it can't - database support is feature flag-gated, so disabling it as as easy as adding one line in your Cargo.toml file. This, however, will obviously also disable some other features that depend on the database, such as authentication through database.

Whether building a custom ORM will be a good idea - only time will tell.

winrid

5 hours ago

I think Django's marketing for perfectionists with deadlines is a bit better than "for lazy developers" :) but excited to see people build "Django, but compiled"

bestouff

4 hours ago

Naah it's perfectly good marketing: "for lazy developers" is way more catchy than "for perfectionists". Look how we discuss that.

Onavo

9 minutes ago

I would suggest avoiding the frontend proc like SCSS pre processors and use a proper bundler like Tailwind instead.

bdaebgi

5 hours ago

>Cot was born out of frustration - the kind that every Rust developer feels when searching for a batteries-included, Django-like web framework

What about Django?

freeone3000

5 hours ago

That would require programming in python, which as everyone knows, is not Rust.

m4tx

5 hours ago

If Django works for you, I'm absolutely not saying you should switch to Cot immediately! Some people like to have as many type-safety and compile-time checks as possible, so that's the crowd we're trying to satisfy.

tonyhart7

5 hours ago

this is rust community, "we" even try oxidizing linux

aside from joke, "I want every good thing about C++ but easiness of high level language" seems the norm

tomaszsobota

5 hours ago

Good stuff, can't wait to see more features :)

Also, +1 for

> struct GownoApp;

johnisgood

an hour ago

For people who don't understand: "gowno" means "shit" in Polish.

m4tx

5 hours ago

LOL, thanks for catching that ;) Will fix!

milne-dev

3 hours ago

The “Ready to Get Started?“ section on the Cot site is line-breaking awkwardly on mobile.

tonyhart7

5 hours ago

another web framework for rust (nice)

I wonder how this par with something like https://loco.rs/

vaylian

5 hours ago

From the article:

> And yes, there’s Loco (which, by the way, has started after the idea for Cot was born), which is a great framework, but [...]

tonyhart7

5 hours ago

which totally say nothing and vague idea, because loco already easy enough and more higher than that would introduce "magic layer" that would really hard to customize (?)

Onavo

7 minutes ago

The major difference between Rails-style frameworks do not support automatic migrations.

giancarlostoro

5 hours ago

What's funny is its obviously in early stages, but its homepage doesn't show an immediate code sample. I find it funny because you are trying to appeal to lazy devs but making them work to get to any code samples.

The golden rule for making a website / readme for any programming language, web framework (or even GUI frameworks) is to have at least one or more code samples, so people can see what coding in your framework looks like.

I'll excuse it since it's a newish project it seems. :)

On that note, I'll be keeping a close eye on this one. This is the kind of web framework I look for, batteries included.

Cot's homepage:

https://cot.rs/

m4tx

4 hours ago

Good point! I'll add some code samples soon, thanks!

hyperbrainer

12 minutes ago

Screenshots of things like the admin panel too.

bkummel

5 hours ago

Frameworks that do “everything” are not a good idea. I’m from the Java ecosystem. Spring is the “batteries included” framework there. If you have migrated any real world application to a new major version once, you’ve learned forever that “all in one” frameworks are bad. Please don’t do it!

Instead, use scaffolding tools, that give you a head start on creating a new project, using smaller, specialized libs.

Also, don’t use an ORM. Just write that SQL. Your future self will be thankful.

stavros

5 hours ago

> Also, don’t use an ORM. Just write that SQL. Your future self will be thankful.

I have never understood this. I've been using the ORM for twenty years now, it's saved me countless hours, and I've very rarely needed to break out of it. When I did, I just wrote an SQL query, and that was it. What's the big deal?

sceptic123

4 hours ago

This depends very much on the size of the code base, the amount of data in the DB and (of course) the quality of the ORM.

It sounds like you are lucky enough that you have never had an ORM generating badly optimised/n+1/over-eager queries that take down a production service. Or perhaps had to debug low level query cache issues causing unexpected problems.

I'm not advocating for plain SQL, just offering some suggestions as to why someone might want you to consider it.

alabastervlog

4 hours ago

It depends on the ORM. I've definitely seen a couple (popular, even) where it's worse than nothing at all, if you're comfortable in SQL. But most of them I'd agree, they're handy.

I think some of the blanket "just don't" comes from people who've had to onboard to projects written by teams that didn't understand SQL, but did (sort of) know how to use an ORM, and blame the ORM for allowing those teams to commit their atrocities. But that doesn't make an ORM a bad thing in capable hands.

stavros

4 hours ago

Ah yeah, my experience is with the Django ORM, with which I've had nothing but good experiences with.

ahmedfromtunis

4 hours ago

Every one of the three points you made in your comment has been disapproved by Django.

It's a framework that does (or at least tries) to do everything (or as much as possible), and it's good. Really, really good.

I'm in the process of upgrading an app of mine after months of abandonment, and the process is so smooth it's boring.

Also, Django's ORM is the closest thing to a perfect tool. Sure, it has some dark corners here and there, but Django's ORM has considerably improved my quality of life as a programmer. Heck, I even moved from SQLite to PostgreSQL in an old project, and all I needed to do is to change a couple of config code.

Oh, and Django is both stable and enjoys a constant pace of updates adding useful features practically at every major version.

m4tx

4 hours ago

Agreed, and what you mention here are the main reasons Cot has been strongly inspired by Django. Whether we'll achieve the same level of stability and ORM ease-of-use for the Rust-preferring community, only time will tell.

iterateoften

4 hours ago

Yeah. I can’t believe the alternatives that people try to glue together compared to Django.

Honestly Django has the best db migrations I have used from any language or library.

When I start a project, even if I am going to access the db from raw sql I start by modeling it in Django just because the rapid changes in data modeling allow me to not even think about it. I just have to think about what I want it to be and not about the changes to get there. Other ORMs or no ORM I am writing alter tables instead of focusing on the data model itself.

Eikon

5 hours ago

> The ORM is very lacking at the moment and the automatic migration generator only works with a small subset of possible operations,

I would have hoped that by 2025, new projects would have moved away from ORMs entirely. They really are a useless abstraction layer that always brings tons of trouble and usually makes queries harder to write.

Looking at the first example in the docs

https://cot.rs/guide/latest/db-models/#retrieving-models

    let link = query!(Link, $slug == LimitedString::new("cot").unwrap()).get(request.db()).await?;
I really don't get the point, and that'll certainly get worse with any somewhat non-trivial query.

Why go through all the trouble of reinventing a new DSL when the SQL equivalent would be so much cleaner?

    SELECT * FROM link WHERE slug = 'cot';

jherdman

5 hours ago

Composability is the often cited benefit. As an example, I can do the following in Active Record (Ruby):

  class Account < ApplicationRecord
    scope :active, -> { where.not(active_at: nil) }

    belongs_to :user
  end

  class User < ApplicationRecord
    scope :born_before, ->(born_on) { where(birthdate: born_on) }
  end

  active_users_with_birthdays_today = Account.active.joins(:user).merge(User.born_before(Date.today))
Contrived, of course, but it's not hard to see how you can use these sorts of things to build up record sorting, filtering, etc. Doing this by hand wouldn't be very fun.

sgarland

5 hours ago

The thought process can be the same in SQL. You can start by writing SELECT * FROM Account; then add your JOIN to User, then add your predicates. Then you can refine it – here, if I’m understanding the code correctly, you’re using User for a JOIN but never return anything from that table, so you could turn it into a semi-join (WHERE EXISTS) and likely get a speed-up.

iterateoften

5 hours ago

> then add your predicates

How are you canonically storing these predicates in code to reuse over 5-10 queries?

Eikon

5 hours ago

I'm not sure why you think you’d need an ORM for that. Most SQL client libraries allow you to compose queries, and query builders, which are not ORMs, can handle that just fine too.

iterateoften

5 hours ago

By the time you have a query builder that will rewrite queries so that column name and table names to be compatible with composition you basically have an ORM.

Especially if you are defining types anyways to extract the data from the sql into.

mathw

5 hours ago

I've yet to see an ORM which doesn't just eventually make everything harder. Especially when it comes to automatic migrations, which seldom seem to take into account production necessities like multi-node deployment, downtime considerations and not destroying your production data silently because it doesn't fit.

submain

5 hours ago

ORMs are one of those things that make sense for really tiny projects but fail to scale once complexity settles in.

iterateoften

4 hours ago

Exact opposite experience.

“SQL strings are one of those things that make sense for really tiny projects but fail to scale once complexity settles in“

Large projects require reuse, composability and easy refactoring. All things ORMs excel at.

On a small code base it is easy to rename a column or add a column, etc.

On a large code base with already 100s of queries using that table, without an ORM it isn’t as straightforward to update all references and ensure that ever place consuming that table has the new column info.

iterateoften

4 hours ago

> like multi-node deployment, downtime considerations

Never had an issue with Django on a large project at a previous $8b startup whose code base went over several major data refactors.

In fact Django’s excellent migrations was specially called out for the reason for our confidence in making large DB refactors.

m4tx

5 hours ago

Writing raw SQL is perhaps indeed easier for simple queries, but put some foreign keys inside or slightly more complex relationships between tables and you'll probably quickly fall into the trap of having to remember your entire database schema to write anything. Yes, the example from the documentation is slightly more complicated, but it checks at compile time the exact column names and types, so you get feedback much quicker than actually running the SQL query.

In addition to that, over the years of writing web services, I always found raw queries much less maintainable. The ORM immediately tells you that you messed up your refactoring, whether it is just renaming a column, or removing a table completely.

Pretty much every ORM (including the one in Cot) also allows you to write your own custom queries if the abstractions are not enough, so there's always this fallback option.

norman784

5 hours ago

> Yes, the example from the documentation is slightly more complicated, but it checks at compile time the exact column names and types, so you get feedback much quicker than actually running the SQL query.

Well sqlx checks at compile time your raw query if you use their macro, at the expense of increased compile times.

iterateoften

5 hours ago

I never understood the hate against ORMs. It always seems like a superiority complex or some claim that SQL is “so simple”.

Yeah SQL is extremely simple to write, that isn’t really the problem ORMs solve for me, but rather they solve composability and reuse of queries.

I think there is a similar vein of people crying about sites not using 100% vanilla js without a framework. They are missing the point or don’t have enough experience with the actual problems the abstractions solve.

stop50

4 hours ago

I am confident in easy SELECT queries, even with multiple tables, but once i have to use JOIN or other advanced things my queries are a mess, returning data i never expected.

schmorptron

5 hours ago

As long as it's still possible to also use SQL queries with it it's fine, right? I know some people who prefer using ORMs and some who like writing SQL.

Eikon

5 hours ago

It’s not fine because ORMs never make sense as an abstraction layer. They try to map concepts that are inherently incompatible. Relational databases are designed around set theory and strict schema constraints, while object-oriented programming relies on hierarchical structures and mutable state.

iterateoften

5 hours ago

Well just because it uses the word object doesn’t mean it is strictly for object oriented programming.

Haskell and Elixir, etc all have ORMs (or rather ecto calls itself a data mapper but functionally it is 1:1 analogous to an ORM in any other language)

fhennig

5 hours ago

I don't think it's a good idea to have a mix of both in a codebase, because then you'll have to be good at both - kind of defeats the purpose.

lelanthran

5 hours ago

> I don't think it's a good idea to have a mix of both in a codebase, because then you'll have to be good at both - kind of defeats the purpose.

When using an ORM you already have to be good at both for any nontrivial query.

p2detar

5 hours ago

My impression is people use ORM not because they lack SQL skills (which is possible), but because it makes object-mapping much easier and with a large count of tables and ever-evolving database, at some point it just feels more natural to drop writing SQL queries and rely solely on the ORM to build up your object graph.

I actually find myself on crosspath where I did start with just SQL but now the database has grown a lot and it is just too much effort to keep writing queries as features pile up. Switching to ORM in one take would be nearly impossible but probably it could work as a step-by-step process, so have both SQL and ORM. Still thinking about this.

preciousoo

5 hours ago

That’s up to each user, no?

csh602

5 hours ago

ORMs, in my experience, fail the hardest when DB admins and web devs butt heads in when and where to create models. It can be an extra hurdle for data flexibility, but it clarifies data architecture at the beginning. In our Django environment, the DB admins won and we added `MIGRATE = False`.

sergioisidoro

5 hours ago

It's 2025, and some ORMs are quite good (eg. Django, ActiveRecord). You can have an ORM with escape hatch of SQL. I do not understand the people who are so against ORMs.

I use ORM query interfaces 80% of the time, and for performance critical queries I can use direct SQL. But the query sanitization, smart preloading and performance checks, schema management and migration tools they often provide, and type checks / hints are really nice features of ORMs.

Furthermore, ORMs are ESPECIALLY useful in teams where you have more junior devs who need these guardrails.

I think the issue here is trying to reinvent a new ORM.

winrid

5 hours ago

Nah. The query is $slug == LimitedString::new("cot")

Also, people like ORMs. Type safety is nice too without having to map manually. Sqlx is also great

lelanthran

5 hours ago

> Also, people like ORMs. Type safety is nice too without having to map manually. Sqlx is also great

Don't you get type safety anyway with parameterised parameters?

winrid

2 hours ago

on return values?

ahmedfromtunis

4 hours ago

I never worked with Rust, but maybe the complexity is due to how the language works.

Using Django's ORM, that would simply be: link=Link.objects.get(slug="cot")

It'd still be very readable and manageable even for complex queries.

alabastervlog

5 hours ago

ORMs are great. They afford abundant opportunities to look like a hero by swooping into a project and cutting a page load of forty seconds to under one second.

whoomp12342

5 hours ago

if you can decompose the query, you can unit test the logic against inmemory sets(or language specific equivalent).

rocky_raccoon

5 hours ago

What is the competitive landscape looking like these days for Rust web frameworks? I couldn't help but feel a bit insecure last time I was exploring the various options because none of them seemed to have the maturity or longevity of frameworks from other languages (for obvious reasons).

Is there one framework that stands out from the rest from an "investment risk" perspective? In other words, if my company is going to choose a framework to build a website, which one has the lowest odds of burning me by becoming abandoned or unsupported?

skldj28d2

5 hours ago

Axum is most likely to be supported long term since it has quite a bit of support and is a Tokio project but it's not nearly as batteries included as something like Rails or Django. I doubt any of the current batteries included Rust web frameworks will last.

norman784

5 hours ago

I would say pick Axum or Actix, these are the go to right now with lower risk to be abandoned, But they aren't batteries included. Here is a list of blessed[0] libraries that might help you to choose the most popular ones in their respective category, but at the end depends on you to pick the one that has the biggest community.

My go to is Axum + sqlx most of the time.

[0] https://blessed.rs

darrenf

5 hours ago

Blog post date says 18th February 2024. Is this a 1yr anniversary post, or a typo? :)

m4tx

5 hours ago

Yeah, it was a typo, just deploying a fix. Thanks!

noodletheworld

5 hours ago

Lots of “Rails but for X” projects exist in various states, for various languages, but have failed to gain traction and stand abandoned.

…like, a lot.

I thiiiink, fundamentally, it’s a harder-than-it-looks problem space and if you come out with something that’s rough and broken, it never gains enough critical mass for it to become self sustaining.

What’s the “pitch”? It’s can’t be “Django but for rust but it’s kind of not ready yet”, bluntly.

So it needs to have some outstanding feature or accumulation of features that let it stand out from the other 30 rust web frameworks. Is there something here?

You really need to call out the “why another rust web framework” in more than just terms of ambition, imo.

singularity2001

4 hours ago

Ok(Response::new_html(StatusCode::OK, Body::fixed(rendered)))

no thank you. if you like it good for you, for me this looks worse than

Body body = BodyFactory.newInstance(BodyConfiguration.OK)

which is still SHORTHER and less cancer

m4tx

an hour ago

That's one of the issues explicitly mentioned in the article ("Request Handler API is far from being ergonomic"). This will get better in the nearest future as it's a major pain point, I'm just thinking of the best API for doing request/responses.

orangeboats

3 hours ago

Your BodyFactory example isn't even functionally the same as the quoted code snippet. Nowhere is the Body::fixed(rendered) equivalent seen, for example.