Coder Social home page Coder Social logo

cuid's Introduction

cuid

Travis-CI

Collision-resistant ids optimized for horizontal scaling and binary search lookup performance.

Status: Deprecated due to security. Use Cuid2, instead.

Note: All monotonically increasing (auto-increment, k-sortable), and timestamp-based ids share the security issues with Cuid. V4 UUIDs and GUIDs are also insecure because it's possible to predict future values of many random algorithms, and many of them are biased, leading to increased probability of collision. Likewise, UUID V6-V8 are also insecure because they leak information which could be used to exploit systems or violate user privacy. Here are some example exploits:

Original Documentation Follows

Currently available for Node, browsers, Java, Ruby, .Net, Go, and many other languages (see ports below — more ports are welcome).

cuid() returns a short random string with some collision-busting measures. Safe to use as HTML element ID's, and unique server-side record lookups.

Example

ESM:

import cuid from 'cuid';

console.log( cuid() );

// cjld2cjxh0000qzrmn831i7rn

Node style:

var cuid = require('cuid');
console.log( cuid() );

// cjld2cyuq0000t3rmniod1foy

Installing

$ npm install --save cuid

Broken down

** c - h72gsb32 - 0000 - udoc - l363eofy **

The groups, in order, are:

  • 'c' - identifies this as a cuid, and allows you to use it in html entity ids.
  • Timestamp
  • Counter - a single process might generate the same random string. The weaker the pseudo-random source, the higher the probability. That problem gets worse as processors get faster. The counter will roll over if the value gets too big.
  • Client fingerprint
  • Random (using cryptographically secure libraries where available).

Fingerprints

In browsers, the first chars are obtained from the user agent string (which is fairly unique), and the supported mimeTypes (which is also fairly unique, except for IE, which always returns 0). That string is concatenated with a count of variables in the global scope (which is also fairly unique), and the result is trimmed to 4 chars.

In node, the first two chars are extracted from the process.pid. The next two chars are extracted from the hostname.

Motivation

Modern web applications have different requirements than applications from just a few years ago. Our modern unique identifiers have a stricter list of requirements that cannot all be satisfied by any existing version of the GUID/UUID specifications:

Horizontal scalability

Today's applications don't run on any single machine.

Applications might need to support online / offline capability, which means we need a way for clients on different hosts to generate ids that won't collide with ids generated by other hosts -- even if they're not connected to the network.

Most pseudo-random algorithms use time in ms as a random seed. Random IDs lack sufficient entropy when running in separate processes (such as cloned virtual machines or client browsers) to guarantee against collisions. Application developers report v4 UUID collisions causing problems in their applications when the ID generation is distributed between lots of machines such that lots of IDs are generated in the same millisecond.

Each new client exponentially increases the chance of collision in the same way that each new character in a random string exponentially reduces the chance of collision. Successful apps scale at hundreds or thousands of new clients per day, so fighting the lack of entropy by adding random characters is a losing strategy.

Because of the nature of this problem, it's possible to build an app from the ground up and scale it to a million users before this problem rears its head. By the time you notice the problem (when your peak hour use requires dozens of ids to be created per ms), if your db doesn't have unique constraints on the id because you thought your guids were safe, you're in a world of hurt. Your users start to see data that doesn't belong to them because the db just returns the first ID match it finds.

Alternatively, you've played it safe and you only let your database create ids. Writes only happen on a master database, and load is spread out over read replicas. But with this kind of strain, you have to start scaling your database writes horizontally, too, and suddenly your application starts to crawl (if the db is smart enough to guarantee unique ids between write hosts), or you start getting id collisions between different db hosts, so your write hosts don't agree about which ids represent which data.

Performance

Because entities might need to be generated in high-performance loops, id generation should be fast. That means no waiting around for asynchronous entropy pool requests, or cross-process/cross-network communication. Performance slows to impracticality in the browser. All sources of entropy need to be fast enough for synchronous access.

Even worse, when the database is the only guarantee that ids are unique, that means that clients are forced to send incomplete records to the database, and wait for a network round-trip before they can use the ids in any algorithm. Forget about fast client performance. It simply isn't possible.

That situation has caused some clients to create ids that are only usable in a single client session (such as an in-memory counter). When the database returns the real id, the client has to do some juggling logic to swap out the id being used.

If client side ID generation were stronger, the chances of collision would be much smaller, and the client could send complete records to the db for insertion without waiting for a full round-trip request to finish before using the ID.

Monotonically increasing IDs

Cuids generated by the same process are monotonically increasing, when less than 10000 cuids are generated within the same millisecond. Generated by different processes, the cuids will still have an increasing value in time if the process clocks are synchronized.

Monotonically increasing IDs are suitable for use as high-performance database primary keys, because they can be binary searched. Pure pseudo-random variants don't meet this requirement.

Tiny

Somewhat related to performance, an algorithm to generate an ID should require a tiny implementation. This is especially important for thick-client JavaScript applications.

Security

Client-visible ids often need to have sufficient random data that it becomes practically impossible to try to guess valid IDs based on an existing, known id. That makes simple sequential ids unusable in the context of client-side generated database keys.

Portability

Most stronger forms of the UUID / GUID algorithms require access to OS services that are not available in browsers, meaning that they are impossible to implement as specified.

Features of cuids

Scalable

Because of the timestamp and the counter, cuid is really good at generating unique IDs on one machine.

Because of the fingerprints, cuid is also good at preventing collisions between multiple clients.

Fast

Because cuids can be safely generated synchronously, you can generate a lot of them quickly. Since it's unlikely that you'll get a collision, you don't have to wait for a round trip to the database just to insert a complete record in your database.

Because cuids are monotonically increasing, database primary key performance gets a significant boost.

Weighing in at less than 1k minified and compressed, the cuid source should be suitable for even the lightest-weight mobile clients, and will not have a significant impact on the download time of your app, particularly if you follow best practices and concatenate it with the rest of your code in order to avoid the latency hit of an extra file request.

Secure

Cuids contain enough random data and moving parts as to make guessing another id based on an existing id practically impossible. It also opens up a way to detect for abuse attempts -- if a client requests large blocks of ids that don't exist, there's a good chance that the client is malicious, or trying to get at data that doesn't belong to it.

Portable

The only part of a cuid that might be hard to replicate between different clients is the fingerprint. It's easy to override the fingerprint method in order to port to different clients. Cuid already works standalone in browsers, or as a node module, so you can use cuid where you need to use it.

The algorithm is also easy to reproduce in other languages. You are encouraged to port it to whatever language you see fit.

Ports:

Short URLs

Need a smaller ID? cuid.slug() is for you. With 7 to 10 characters, .slug() is a great solution for short urls. Slugs may grow up to 10 characters as the internal counter increases. They're good for things like URL slug disambiguation (i.e., example.com/some-post-title-<slug>) but absolutely not recommended for database unique IDs. Stick to the full cuid for database keys.

Be aware, slugs:

  • are less likely to be monotonically increasing. Stick to full cuids for database lookups, if possible.

  • have less random data, less room for the counter, and less room for the fingerprint, which means that all of them are more likely to collide or be guessed, especially as CPU speeds increase.

Don't use them if guessing an existing ID would expose confidential information to malicious users. For example, if you're providing a service like Google Drive or DropBox, which hosts user's private files, favor cuid() over .slug().

Questions

Is this a replacement for GUID / UUID?

No. Cuid is great for the use case it was designed for -- to generate ids for applications which need to be scalable past tens or hundreds of new entities per second across multiple id-generating hosts. In other words, if you're building a web or mobile app and want the assurance that your choice of id standards isn't going to slow you down, cuid is for you.

However, if you need to obscure the order of id generation, or if it's potentially problematic to know the precise time that an id was generated, you'll want to go with something different.

Cuids should not be considered cryptographically secure (but neither should most guid algorithms. Make sure yours is using a crypto library before you rely on it).

Why don't you use sha1, md5, etc?

A sha1 implementation in JavaScript is about 300 lines by itself, uncompressed, and its use would provide little benefit. For contrast, the cuid source code weighs in at less than 100 lines of code, uncompressed. It also comes at considerable performance cost. Md5 has similar issues.

Why are there no dashes?

Almost all web-technology identifiers allow numbers and letters (though some require you to begin with a letter -- hence the 'c' at the beginning of a cuid). However, dashes are not allowed in some identifier names. Removing dashes between groups allows the ids to be more portable. Also, identifier groupings should not be relied on in your application. Removing them should discourage application developers from trying to extract data from a cuid.

The cuid specification should not be considered an API contract. Code that relies on the groupings as laid out here should be considered brittle and not be used in production.

Credit

Created by Eric Elliott.

cuid's People

Contributors

cadienvan avatar cbettinger avatar crabmusket avatar duailibe avatar ericelliott avatar gitter-badger avatar gjcoombes avatar gmaclennan avatar jhermsmeier avatar k2s avatar kennylavender avatar marcoonroad avatar markherhold avatar matthiasg avatar max-mapper avatar maxwellgerber avatar mplanchard avatar n8io avatar nicmitchell avatar niftylettuce avatar paambaati avatar pieterjandesmedt avatar renovate-bot avatar scop avatar sorenbs avatar theodesp avatar therealklanni avatar thibaultmeyer avatar wbinnssmith avatar zakame avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cuid's Issues

navigator is not defined

I could being doing something really stupid (as is the case normally) but I can't get my tests to pass in Node with cuid.

error trying to resolve DateInputViewModel navigator is not defined ReferenceError: navigator is not d
efined

If I dig a little further, it looks like cuid is expecting the window.navigator to exist... but obviously this is not the case when running in a Node process. I am using Testem's launchers to run this particular suite of tests, and perhaps that is where the error lies. Maybe Testem isn't setting an environment variable correctly and therefore some kind of cuid check of if process.env === node is failing?

Any ideas would be appreciated.

Go port

Hi,

If you are interested in mentioning it in your README file, I have ported this to Go. The package is not 100% finished but will be pretty soon.

http://github.com/lucsky/cuid

Thanks for this lib :)

slug() is generating 7 character IDs

The documentation states that IDs generated through cuid.slug() weigh in at 8 characters, however the ones I'm seeing are 7 characters. Is this expected behaviour? Does the documentation mean they will be up to 8 characters?

Add option to reconstruct timestamp

I'm using cuid for logging stuff into a document database in objects like this:

{
  id: cuid(),
  timestamp: new Date.getTime(),
  type: 'content-specific',
  content: {...some_data}
}

If I could somehow safely reconstruct the timestamp back from id, I could omit having to store the timestamp in the database thus saving myself a lot of space.

Any option to add such feature?

Status of cuid

Hi everyone,

I'm wondering what is the dev status of this library, is it still actively maintained?
Is it safe to bet on it for a new Node project?

Thanks for your answer :)

IDs are predictable, should clarify in README

I was looking through this project since it's a dependency for something else I was checking out.

I noticed that you are using Math.random(). This is fine but if so you shouldn't claim that the ids are unguessable:

Cuids contain enough random data and moving parts as to make guessing another id based on an existing id practically impossible.

Since Math.random() is not cryptographically secure it's easy to predict the next values. I would remove the two security/secure paragraphs completely and add a warning instead.

EDIT: Just for fun I wrote a proof of concept here that can predict all CUIDs(excluding timestamp portion) after seeing four consecutive ids. It's for node v4/v5 only since they've updated their RNG algorithm but the approach for later versions is similar.

Need to test with bundlers

Because the popular bundling tools may not bundle stuff from node_modules our package.json may need to point to bundled versions of the library, instead of individual modules. I've tried doing this with Browserify, but then Webpack gives weird warnings to all the users of our module (I think -- it used to, anyway).

We could try to accomplish this with rollup.

For this to be complete we need to test:

  • npm install from the npm tar bundle
  • Build and use in Webpack
  • Build and use with Browserify
  • Build and use with Rollup

cc @MarkHerhold @gmaclennan

Validation

Is there any way to validate a cuid? For example to distinguish it from a random string?

Can you provide some example?

module.exports = (function() {

I try the following. only slug(), and fingerprint return 5 chars.

How do I get longer one?

Regards,

var cuid = require('cuid');
var id = new cuid();

return function(req, res, next) {

console.log('cuid module');

//console.log(cuid);
//console.log(id);

//console.log(cuid.fingerprint());  // short, 5 chars
//console.log(cuid.slug());   // work, short one
console.log(cuid.cuid());
//console.log(cuid.nodePrint());

console.log(id.cuid());
//console.log(id.fingerprint());
//console.log(id.slug());   // work, short one
//console.log(id.nodePrint());

next();

}

})();

Add Sauce Labs

You can create a bin/env.sh file in a bin dir and add it to .gitignore:

!/bin/bash
set KEY=value

Be sure to include a bin/env.sh.example file and check that one into git.

Then as part of the scripts:

  "test:browsers": "source bin/<filename>.sh"

Checklist

  • Create bin/env.sh
  • Create bin/env.sh.example
  • Update package.json
  • Add bin/env.sh instructions to README

Will cuid length always be 25?

Hi,

Is cuid will always return a length 25 string ?
Need to know for setting VARCHAR length.
Couldn't find an exact answer about it.

Thanks !

Issue with checking for CommonJS

The standalone built versions (./dist) of cuid currently do only one of the two typical checks for CommonJS based amd. See:
else if (typeof module !== 'undefined') { module.exports = api; } -- Line 104 dist/browser-cuid.js

when compared to the standard practice of:
if ( typeof module === "object" && typeof module.exports === "object" ) {

This caused a bit of a headache recently as another dependency (angular-mocks) when run through Karma/Jasmine actually stores a function in window.module. I wasn't sure the proper procedure for submitting a fix as it looks like the ./dist versions are not built through the npm scripts.

Thanks

support web workers

Please add support for web workers.

cuid() currently throws an exception in web workers since navigator.mimeTypes is not available in that context.

Generally, for the fingerprint I suggest to collect various strings as a whole, gracefully handling errors, and then create a fingerprint out of that (arbitrary length) string using some hash function - like MD5, but perhaps something more lightweight.

Something in this direction:

api.fingerprint = function browserPrint() {

  var things = [];

  try {
    for (var i = 0; i < navigator.mimeTypes.length; i++) {
      things.push(navigator.mimeTypes[i]);
    }
  } catch (e) {
    // ignore errors
  }

  try {
    things.push(navigator.userAgent);
  } catch (e) {
    // ignore errors
  }

  // maybe add some more...

  things.push(api.globalCount());

  return someHashFunction(things.join(""));
};

I think you get the idea...

node-cuid .vs. node-uuid comparison (thoughts?)

Hi, node-uuid author here. I just had this module brought to my attention and thought we might compare notes. I haven't done a thorough investigation, but it seems like cuid is pretty similar to node-uuid's RFC4122 v1 implementation.

cuid timestamp & cuid counter

RFC4122 uses a timestamp system that includes both the timestamp and counter concepts. The RFC timestamp interval is 100-nanoseconds, but in environments that lack this resolution, clients can use a counter of ids generated during the current timestamp interval to emulate the higher precision, which is what node-uuid does.

In terms of how these values contribute to uniqueness, it's about the same; the RFC timestamp is 64 bits.
The cuid timestamp + counter is ~62 bits

cuid fingerprint & cuid random

cuid attempts to generate a per-client unique id in the form of fingerprint. In cuid (browser) this is built from these values:

  • userAgent.length - Only unique to browser version + OS
  • mimeTypes.length - Only unique to browser (+ plugins? I'm not sure what contributes to this honestly)
  • (paraphrasing) Object.keys(window).length - Only unique to browser + application runtime

... or in cuid (node):

  • process id: 0 - 1295, with clustering, if not outright duplication, in production environments where hosts all have same boot process.
  • checksum(hostname): 0 - 2500 (clustering around average hostname checksum, possibly clustering in environents where hosts are sequentially named - e.g. checksum is same for "host03", "host12", "host21", and "host30")

For the reasons noted above, I'm concerned about how unique this "fingerprint" actually is in production.

node-cuid uses Math.random(), which is (by definition) an RNG of uncertain quality.

Meanwhile in the RFC/node-uuid ...

The node property should be either the host MAC address (unique to a fairly high degree of certainty) if available, or set randomly if not. In node-uuid it's set randomly.

node-uuid only uses Math.random() as the RNG of last resort, preferring higher-quality crypto implementations where available.

The RFC also includes a 14-bit clockseq value which is initialized randomly, and which increments any time there is a discontinuity detected in the system clock (e.g. if the clock regresses backward). This is similar to cuid's random value, with the added benefit of preventing duplicates if something happens to the system clock, which is a feature I don't see in node-cuid.

In terms of how these contribute to uniqueness, the cuid fingerprint + cuid random is ~ 62 bits (21 + 41 bits. Meanwhile the RFC node + clockseq is also 62 bits (48 + 14 bits).

Summary

node-cuid offers strikingly similar features to RFC4122 v1 UUIDs, just in a slightly different form factor. While the node-cuid IDs are somewhat shorter (25 chars vs. 40 chars), that's simply a presentation choice; (e.g. converting from RFC notation to cuid notation and back is fairly trivial). In fact, I'm curious why node-cuid doesn't use base-62, for shorter-still ids, since that's one of the selling points.

More importantly, I don't see anything in cuid that suggests it is better at avoiding collisions. In fact, the fingerprint issues, the reliance on Math.random(), and lack of clock regression detection logic suggest that it will be worse, not better, than an RFC compliant implementation.

(FWIW, I've spent a lot of time looking at the RFC trying to see if there's a way it might be improved. It's actually a very well thought-out spec, which is why I decided to focus on a rigorous implementation for node-uuid. The one aspect of it I'm not a fan of is the choice of gregorian epoch + 100-nanosecond increments for the timestamp field. I think the spec would have been better served with a standard unix epoch + 1 second increments, with an explicit counter field, akin to what cuid has to handle id sequencing with a given timestamp unit. But the end result is more or less the same, so it's not that big a deal.

Anyhow, hope this is useful. And please do point out anywhere I may have misunderstood what you're doing.

Cheers!

Timestamp

Can I get the timestamp from the generated id?

`crypto.getRandomValues`

How do you feel about using getRandomValues from the Web Crypto API in the environments that support it for randomBlock?

Cache fingerprint

wouldn't it make sense to store fingerprint in a variable and only run it once when needed?

TypeError: process.pid is undefined

Didn't update any package or system environment, but today when I call cuid() I get

TypeError: process.pid is undefined
nodePrint
[path to my react component]
cuid
webpack:///./~/cuid/dist/node-cuid.js?:49:23

Using
cuid: 1.3.8
webpack: 2.2.0
webpack-dev-server: 2.2.0
node v6.9.4
npm v3.10.10
yarn 0.20.3

Tried on [email protected], got the same result.

Padding on timestamp for proper sorting

Is there any specific reason (along making it a bit longer than absolutely necessary) why the timestamp does not contain some padding (beginning zeros)... if it would, I think it could be used as a time order criteria on standard ASCII sorting

c var bounds not checked in slug() implementation

In slug() impl, the c value is not checked to be in the discrete values range like it is in cuid(). c is then directly incremented after usage.

c = (c < discreteValues) ? c : 0;

Intensive use of slug without any calls to fingerprint could lead to overflow.

Usage in react-native

More of a comment here for other react-native users that might run into the same issue, than a bug specifically, but because react-native doesn't provide a userAgent or mimeTypes by default, using cuid will throw an error.

This can be worked around by defining dummy values before requiring cuid;

global.navigator.mimeTypes = ''; //browser-fingerprint only checks the length property so an empty string is fine
global.navigator.userAgent = 'reactnative';

I did try using the node version but rn also doesn't set a process.pid so runs into the same issue.

duplicate key error

I got the following error.

When the process too fast, it generate duplicate key.

MongoError: E11000 duplicate key error index

Either JavaScript Pseudo random is not good.

I also think Timestamp have a problem too by looking at the key.

Let say, node is running with cluster and more then 10 thread. It is highly possible that both Timestamp and Pseudo random will be the same with high hit.

A way to let user add just one digit will be good enough I guess.

Database index fragmentation

Eric, you write that the sequential nature of cuid makes for better performance when used as primary keys in databases. I'm currently trying to choose what id concept to use and the more I read the more I understand that this is hard.

It seems that both the placement of the timestamp part of the uuid AND big/little endian concept of different database engines and OSes matters. Do you have any plans to make cuid more compatible with different RDBMs by making the timestamp style tweakable?

Maybe some interesting reading: https://github.com/richardtallent/RT.Comb

I'm sorry to say that I don't have the competence to be able to PR something. I stumbled over cuid while researching. I have always held you high for competence and innovation in the Javascript community, and was hoping that "this is it, this could solve my id needs" :)

cuid as partition key

Due to the c{timestamp}... structure, I have concerns about "todays" items creating a hot spot in a distributed data store for my use-case (long history of items, todays items are used heavily, using aws DynamoDB).

Thoughts on the validity of my concern?

Ruby port

Hey,

I liked your cuid project so I ported it to Ruby, you can see it here: http://github.com/iyshannon/cuid.

Please check it out and let me know what you think, I haven't published it to RubyGems yet as I wanted to get your OK before doing so.

Thanks,
Ian

Support Node, Browsers, WebWorkers, & ReactNative

The JS version of cuid needs to support all of these targets:

We'll use feature detection to select the correct entropy source and return the right fingerprint() function for the environment.

Ideally, we should select entropy sources supported by all of the above environments.

How are these sequential? (meta)

... If they're generated on different browsers or machines, and then inserted to the database later, won't they be in some random order? Am I totally missing the point? (I think so, sorry about that!) This looks really cool, but I'm struggling to understand the bit about them being sequential. If they were only sequential because they were being generated on ONE machine, then why wouldn't you just use an auto-increment int or bigint?

ID spoofing

Hi,

Was wondering what your thoughts were on the potential of spoofed Id's originating from untrusted clients.

One of the things that appeals to me about cuids are the fact that id's are more or less sequential (assuming consistent time sources), which means I can use them as PK's in my DB and won't get burnt on inserts (due to the rows being stored.as a clustered index),

This does however leave an unsavory taste in my mouth - as an untrusted client could screw with my DB index by generating unique, but non sequential id's.

I was thinking of performing some sanity checking server side on any new id's generated client side. Nothing too restrictive, I would probably just check the basic format is correct and that the timestamp fits within a suitably large window. I then noticed this in the README:

"The cuid specification should not be considered an API contract. Code that relies on the groupings as laid out here should be considered brittle and not be used in production."

Do you believe this applies in the stated context?

Regards
Rob

Landing date for 2.0.0

For reasons related to a problem in a CUID 1.3.8 dependency, I'm very excited for the jump to 2.0.0

Any word on when it lands in NPM? Any API changes to know about?

Thanks!

Make the starting symbol customizable

Would be great to have a way to customize the starting character.
It could be given as a parameter to the cuid() function. The "c" could be the default if not given...

If customizable, one could create specific classes of IDs that would allow some backend decisions based on the type of ID received...

Modularize

Please complete #24 first.

Stop using the hacky concat build.

  • Use ES6 modules
  • Drop applitude support (it's obsolete)
  • Use separate client/server build entry points and share common features between them.
.
└── cuid
    ├── build
    │   ├── client
    │   └── server
    ├── source
    │   ├── client
    │   └── server
    └── test
        ├── client
        └── server

Ignore build directory in diffs

You can ignore build files in diffs.

Create a .gitattributes file in the repo root:

build    -diff

v1.3.0 fails on require

The latest release/tag and npm package, v1.3.0, has in package.json "main": "./build/server/cuid.js", but includes no folder build.

The package.json also still references the dist folder, which was included in v1.2.4, but is not in v1.3.0.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.