pnpm: ένα αντίγραφο κάθε πακέτου, για όλα τα έργα σου
Ο pnpm είναι ένας διαχειριστής πακέτων για το Node.js — το εργαλείο που κατεβάζει και τοποθετεί τις βιβλιοθήκες που χρησιμοποιεί το πρόγραμμά σου. Αντί να κρατά ένα αντίγραφο από κάθε βιβλιοθήκη μέσα σε κάθε έργο, κρατά ένα αντίγραφο σε κοινό χώρο και δίνει σε κάθε έργο έναν σύνδεσμο προς αυτό. Έτσι δεν γεμίζει ο δίσκος με τα ίδια αρχεία, και ο κώδικας δεν μπορεί πια να δουλέψει με βιβλιοθήκες που δεν δήλωσε ποτέ.

Δύο λέξεις πρώτα
Φαντάσου μια γειτονιά με δέκα σπίτια και, σε κάθε σπίτι, μια βιβλιοθήκη με τα ίδια διακόσια βιβλία. Κανείς δεν δανείζεται από τον γείτονα· ο καθένας αγοράζει το δικό του αντίγραφο. Τα ράφια γεμίζουν, τα διπλότυπα πληθαίνουν, και κάθε φορά που βγαίνει καινούργια έκδοση ενός βιβλίου πρέπει να την αγοράσουν δέκα φορές.
Ο pnpm στήνει μία κεντρική βιβλιοθήκη στη γειτονιά. Κάθε βιβλίο υπάρχει μία φορά, σε έναν κοινό χώρο. Τα σπίτια δεν παίρνουν αντίγραφο· παίρνουν έναν σύνδεσμο — μια ταμπέλα που λέει «αυτό το βιβλίο είναι εκεί». Στο ράφι του κάθε σπιτιού φαίνεται πως το έχει, αλλά τα χαρτιά που κάθονται στον δίσκο είναι ένα, όχι δέκα.
Αυτός ο κοινός χώρος λέγεται store, και ο φάκελος που γεμίζει μέσα στο έργο σου λέγεται node_modules — το σημείο όπου το Node.js ψάχνει τις βιβλιοθήκες όταν το πρόγραμμα ζητά μία. Στον δικό μας κλάδο ο φάκελος αυτός είναι γνωστός για το μέγεθός του: χιλιάδες αρχεία, εκατοντάδες πακέτα, και η ίδια ακριβώς δουλειά αντιγραμμένη σε κάθε φάκελο έργου.
Υπάρχει όμως και ένα δεύτερο μισό που δεν φαίνεται με την πρώτη ματιά, και είναι, κατά τη γνώμη μου, το πιο χρήσιμο. Στον παλιό τρόπο, όταν εγκαθιστάς μία βιβλιοθήκη, ο διαχειριστής βάζει στο top level του node_modules και όλες τις εξαρτήσεις της βιβλιοθήκης — έναν επίπεδο σωρό από πακέτα που δεν ζήτησες ποτέ. Ο κώδικός σου μπορεί τότε να απλώσει το χέρι, να πάρει κάτι από αυτόν τον σωρό και να δουλέψει. Δουλεύει σήμερα· αύριο που θα αλλάξει έκδοση η βιβλιοθήκη και το πακέτο φύγει από τον σωρό, ο κώδικάς σου σκάει, και ψάχνεις ένα σφάλμα που το προκάλεσε κάτι που δεν έγραψες ποτέ.
Ο pnpm σου δείχνει μόνο ό,τι δήλωσες. Αν δεν το έγραψες στο package.json — το αρχείο όπου ένα έργο Node.js καταγράφει τι χρειάζεται — το require() αποτυγχάνει με MODULE_NOT_FOUND. Δεν είναι αστοχία: είναι η δουλειά του.
Δύο πράγματα, λοιπόν, κρατάς από εδώ: λιγότερος χώρος στον δίσκο, και περισσότερη πειθαρχία στις εξαρτήσεις σου.
Τι κάνει
Ο pnpm είναι διαχειριστής πακέτων: εγκαθιστά, αφαιρεί, αναβαθμίζει και τακτοποιεί τις βιβλιοθήκες που χρησιμοποιεί ένα έργο Node.js. Κάνει όσα κάνει το npm, με άλλη λογική στο πού ζουν τα αρχεία.
Πρώτα απ' όλα κρατά lockfile — το αρχείο pnpm-lock.yaml, που καταγράφει την ακριβή έκδοση κάθε πακέτου που εγκαταστάθηκε, μαζί με το δέντρο των εξαρτήσεών του. «Lockfile» σημαίνει αρχείο που κλειδώνει τις εκδόσεις: δύο μηχανήματα, δύο συνάδελφοι, δύο φορές σε CI, φέρνουν ακριβώς τα ίδια πακέτα. Χωρίς αυτό, μια εγκατάσταση που έγινε τον Μάρτιο και μία που έγινε τον Νοέμβριο μπορεί να μη μοιάζουν καθόλου, και το σφάλμα να μη βγαίνει σε κανέναν από τους δύο.
Δεύτερο, έχει κοινό store: κατεβάζει κάθε πακέτο μία φορά στον δίσκο, και μετά όλα τα έργα του μηχανήματος δείχνουν εκεί. Η δεύτερη εγκατάσταση του ίδιου πακέτου δεν κατεβάζει τίποτα και δεν αντιγράφει τίποτα.
Τρίτο, υποστηρίζει workspaces: ένα αποθετήριο που περιέχει πολλά πακέτα, τα οποία μοιράζονται εξαρτήσεις και εντολές. Ο όρος που συναντάς γι' αυτό είναι monorepo — «ένα αποθετήριο, πολλά προγράμματα» — και είναι η περίπτωση όπου ο κοινός χώρος μετράει περισσότερο, γιατί δέκα πακέτα που χρησιμοποιούν και τα δέκα το ίδιο εργαλείο δεν το κρατούν δέκα φορές.
Τέταρτο, στα pipelines (τις αυτοματοποιημένες σειρές εργασιών που τρέχουν σε κάθε αλλαγή κώδικα, γνωστές ως CI) δίνει σταθερές εγκαταστάσεις: διαβάζει το lockfile, δεν μαντεύει εκδόσεις, και μπορεί να κρατήσει το store σε cache ανάμεσα σε δύο εκτελέσεις. Πρακτικά, το βήμα «εγκατάσταση εξαρτήσεων» που κρατούσε λεπτά πέφτει σε δευτερόλεπτα, με τα ίδια ακριβώς πακέτα.
Πέμπτο, έχει ρυθμίσεις για τη μορφή του node_modules. Η σημαντικότερη λέγεται node-linker — ο τρόπος με τον οποίο χτίζει τον φάκελο. Στην προεπιλογή χρησιμοποιεί συνδέσμους και μια διάταξη που κρατά κάθε πακέτο κοντά σε όποιον το δηλώνει· με node-linker=hoisted φτιάχνει έναν επίπεδο φάκελο σαν του npm, για εργαλεία που δεν ξέρουν να δουλέψουν αλλιώς. Είναι διακόπτης συμβατότητας, όχι καλύτερη πρακτική.
Τι δεν κάνει
Δεν είναι runtime. Δεν εκτελεί τον κώδικά σου και δεν αντικαθιστά το Node.js· σταματά στη διαχείριση των αρχείων των βιβλιοθηκών. Ό,τι τρέχει το πρόγραμμά σου το τρέχει το Node.
Δεν διορθώνει εργαλεία που περιμένουν επίπεδο node_modules. Υπάρχουν προγράμματα και plugins που ψάχνουν μια βιβλιοθήκη στο top level του φακέλου, γιατί έτσι τα βρήκε επί χρόνια με το npm. Με τον pnpm αυτό μπορεί να μη δουλέψει, και τότε ενεργοποιείς hoisting — τη μετακίνηση εξαρτήσεων προς τα πάνω, ώστε να φαίνονται στο top level — με node-linker=hoisted ή με τη σημαία --shamefully-hoist. Η ίδια η ονομασία της δεύτερης τα λέει όλα: είναι υποχώρηση, και χαλαρώνει την αυστηρότητα που είναι το νόημα του εργαλείου.
Δεν κρύβει τα λάθη των άλλων πακέτων. Αν ένα πακέτο ζητά βιβλιοθήκη που δεν δήλωσε, θα το δεις με MODULE_NOT_FOUND — όχι γιατί ο pnpm είναι σκληρός, αλλά γιατί ο προηγούμενος διαχειριστής το κάλυπτε. Το σφάλμα υπήρχε πάντα· ο pnpm απλώς δεν το κρύβει πια. Η διόρθωση είναι μία γραμμή στο package.json του έργου σου.
Δεν είναι εργαλείο ανάπτυξης (deployment). Μπορεί να σε βοηθήσει να φτιάξεις μικρότερες εικόνες Docker — τις συσκευασίες που τρέχουν σε παραγωγή — αλλά τα κοντέινερ, τα μητρώα εικόνων και η ροή της παραγωγής παραμένουν δουλειά άλλων εργαλείων.
Δεν είναι «το npm με άλλο όνομα» σε όλα. Δεν είναι σταγονίδιο: αλλάζει το πού ζουν τα αρχεία, και άρα αλλάζει το τι βλέπει ο κώδικας. Σε έργο που δουλεύει χρόνια με φλατ φάκελο, η μετάβαση θέλει ένα πέρασμα ελέγχου, όχι ένα pnpm install και ελπίδα.
Πώς το χρησιμοποιείς
Εγκαθιστάς τον pnpm μία φορά στο σύστημα:
npm i -g pnpm
Αν το Node σου είναι σύγχρονο, υπάρχει και ο δρόμος του Corepack, που δεν απαιτεί καθολική εγκατάσταση:
corepack enable
Ύστερα δουλεύεις μέσα στον φάκελο του έργου σου. Για να ξεκινήσεις ένα νέο έργο:
pnpm init -y
Για να προσθέσεις βιβλιοθήκη:
pnpm add express
Για να εγκαταστήσεις ό,τι καταγράφει το package.json και το lockfile — αυτό τρέχεις σε κάθε νέο μηχάνημα και σε κάθε CI:
pnpm install
Για εργαλείο που το χρειάζεσαι μόνο όσο γράφεις κώδικα (δοκιμές, έλεγχος τύπων, μορφοποίηση):
pnpm add -D typescript
Για να τρέξεις μια εντολή που όρισες στο package.json:
pnpm run build
Και για να καθαρίσεις ό,τι δεν χρησιμοποιεί πια κανένα έργο από τον κοινό χώρο:
pnpm store prune
Η ροή είναι απλή: init, add, install, run. Ό,τι κάνει το npm, το κάνει και ο pnpm με το ίδιο σχήμα λέξεων.
Πώς το οδηγείς από το κέλυφος — και γιατί δεν είναι MCP
Ο pnpm δεν είναι MCP server: δεν είναι υπηρεσία που τη δηλώνεις σε έναν βοηθό για να την καλέσει, ούτε κάτι που τρέχει στο παρασκήνιο. Είναι εργαλείο γραμμής εντολών με υποεντολές — το καλείς από το τερματικό, τελειώνει, και φεύγει. Δεν χρειάζεται να το δηλώσεις πουθενά, και δεν πληρώνεις τίποτα σε φόρτο πλαισίου γι' αυτό: το μοντέλο δεν κουβαλά κανένα σχήμα του.
Αν το οδηγείς μέσα από έναν αυτοματισμό ή έναν βοηθό, οι δύο εντολές που αρκούν είναι αυτές:
pnpm install --frozen-lockfile
και
pnpm run <script>
Η πρώτη λέει «εγκατέστησε ακριβώς ό,τι λέει το lockfile, και αν δεν ταιριάζει με το package.json, σταμάτα με σφάλμα» — αυτό θέλεις σε CI, γιατί μια σιωπηλή αλλαγή έκδοσης σε ένα pipeline είναι χειρότερη από ένα κόκκινο βήμα. Η δεύτερη τρέχει όποια εργασία έχεις ορίσει στο έργο σου.
Για μια μεμονωμένη βιβλιοθήκη, χωρίς να μπει στο έργο, υπάρχει το pnpm dlx, ο αδελφός του npx. Δεν χρειάζεται τίποτα άλλο — ούτε διακομιστής, ούτε ρύθμιση.
Η δοκιμή μας με τα χέρια
Τα νούμερα δεν τα πήραμε από τη σελίδα του εργαλείου· τα μετρήσαμε. Σύμφωνα με ό,τι κάναμε, στήσαμε ένα καθαρό έργο, βάλαμε μέσα express@4.21.2 — μια από τις πιο διαδεδομένες βιβλιοθήκες για διακομιστές στο Node — και τρέξαμε την ίδια ακριβώς εγκατάσταση δύο φορές, μία με npm και μία με pnpm.
Το πρώτο εύρημα φαίνεται με μια ματιά στον φάκελο. Το npm άπλωσε 67 πακέτα στο top level του node_modules. Ο pnpm άφησε ένα: μόνο το express που δηλώσαμε. Τα υπόλοιπα εξήντα έξι είναι εκεί — μέσα στον κοινό χώρο, σε μια διάταξη που τα κρατά προσβάσιμα μόνο σε όποιον τα δήλωσε.
Το δεύτερο εύρημα είναι η παγίδα μας, και είναι το πιο χρήσιμο κομμάτι του άρθρου. Γράψαμε ένα μικρό πρόγραμμα που ζητά require('ms') — μια βιβλιοθήκη που δεν δήλωσε κανείς, αλλά που είναι εξάρτηση του express. Με το npm, το πρόγραμμα δουλεύει: βρίσκει το «φάντασμα» στον επίπεδο σωρό. Με τον pnpm σκάει με MODULE_NOT_FOUND. Ίδιος κώδικας, ίδιο έργο, ίδια βιβλιοθήκη — και η διαφορά δεν είναι σφάλμα του pnpm: είναι η απόδειξη ότι ο κώδικας στηριζόταν σε κάτι που δεν είχε δηλώσει.
Το τρίτο νούμερο αφορά τον δίσκο. Στήσαμε τρία έργα με τις ίδιες εξαρτήσεις. Με το npm κατέλαβαν 11 MB· με τον pnpm 6 MB, γιατί τα αρχεία μοιράζονται από τον κοινό χώρο και δεν διπλασιάζονται. Να το πούμε και ανάποδα, για να μη το παρουσιάσουμε καλύτερο απ' ό,τι είναι: στο ένα έργο η διαφορά ήταν μηδαμινή — γύρω στα 3 με 4 MB και στις δύο περιπτώσεις. Το κέρδος αρχίζει όταν πλήθαίνουν τα έργα.
Το τέταρτο είναι ο χρόνος, και εδώ θέλω να είμαι συγκεκριμένη γιατί εύκολα γίνεται υπερβολή. Με τις κρυφές μνήμες ζεστές, στο ίδιο μηχάνημα, το npm πήρε 9,1 δευτερόλεπτα και ο pnpm 6,3 για το ίδιο έργο. Είναι μία μέτρηση, όχι συγκριτικό αξιολόγησης· οι χρόνοι εγκατάστασης κινούνται πολύ με το δίκτυο και τη στιγμή. Το κρατώ ως ένδειξη, όχι ως υπόσχεση.
Από τα μητρώα, για την ταυτότητα του εργαλείου: τελευταία έκδοση 12.18.0, δημοσιευμένη 5 Νοεμβρίου 2026· άδεια MIT· το πεδίο engines ζητά Node 18 ή νεότερο· μηδέν κανονικές εξαρτήσεις και 14 προαιρετικές, που είναι τα δυαδικά αρχεία ανά πλατφόρμα· μέγεθος πακέτου 4.426.497 bytes, δηλαδή περίπου 4,4 MB· και 325.920.735 λήψεις την εβδομάδα. Στο GitHub το αποθετήριο έχει 37.047 αστέρια, 1.985 forks και 198 ανοιχτά θέματα, με πρώτο commit στις 28 Ιανουαρίου 2016 και τελευταία δραστηριότητα σήμερα.
Τι κοστίζει
Το εργαλείο είναι δωρεάν: άδεια MIT, καμία συνδρομή, κανένα όριο χρήσης. Ό,τι πληρώνεις, το πληρώνεις σε πόρους του μηχανήματός σου.
Σε χώρο. Το ίδιο το πακέτο κατεβάζει 4.426.497 bytes — περίπου 4,4 MB — με μηδέν κανονικές εξαρτήσεις, που σημαίνει ότι δεν φέρνει μαζί του άλλα πακέτα. Οι 14 προαιρετικές εξαρτήσεις είναι δυαδικά αρχεία ανά πλατφόρμα, και κατεβαίνει μόνο αυτό που ταιριάζει στο σύστημά σου. Δική μας μέτρηση: τρία έργα με τις ίδιες εξαρτήσεις κατέλαβαν 11 MB με npm και 6 MB με pnpm.
Σε χρόνο. Δική μας μέτρηση, με ζεστές κρύπτες: 9,1 δευτερόλεπτα με npm, 6,3 με pnpm, για το ίδιο έργο. Μία μέτρηση, όχι συγκριτικό αξιολόγησης — ο χρόνος εξαρτάται πολύ από το δίκτυο.
Σε πλαίσιο μοντέλου (tokens). Μηδέν σταθερό κόστος. Δεν είναι MCP server, δεν δηλώνεται πουθενά, και το μοντέλο δεν σηκώνει κανένα σχήμα εργαλείου γι' αυτό. Αν ένας βοηθός το χρησιμοποιεί, το κόστος είναι οι ίδιες οι δύο εντολές που θα έδινε άλλωστε.
Σε κόπο, που δεν είναι δωρεάν. Ο pnpm απαιτεί να δηλώνεις ό,τι χρησιμοποιείς. Σε νέο έργο αυτό είναι δώρο· σε έργο που στηρίζεται χρόνια σε αδήλωτες βιβλιοθήκες, είναι δουλειά μία φορά — και τη μετράς με το πόσα MODULE_NOT_FOUND θα δεις στην πρώτη εκτέλεση.
Και μια επισήμανση ειλικρίνειας: ό,τι γράφουμε εδώ για ταχύτητα και χώρο είναι μετρημένο από εμάς, αλλά η ίδια η υπόσχεση του κατασκευαστή για μεγάλα monorepos δεν τη δοκιμάσαμε — δεν στήσαμε δέκα πακέτα σε ένα αποθετήριο. Το λέμε, αντί να το περάσουμε σαν δεδομένο.
Πότε αξίζει
Αξίζει, πρώτα, όταν έχεις πολλά έργα με κοινές εξαρτήσεις, ή όταν δουλεύεις σε monorepo. Εκεί ο κοινός χώρος δεν είναι λεπτομέρεια: δέκα πακέτα που χρησιμοποιούν το ίδιο εργαλείο δεν το κρατούν δέκα φορές, και ταιριάσματα εκδόσεων ανάμεσα στα πακέτα γίνονται θέμα που το χειρίζεται το εργαλείο.
Αξίζει, δεύτερον, όταν θέλεις σταθερές εγκαταστάσεις. Το pnpm-lock.yaml κλειδώνει τις εκδόσεις, και μαζί με το --frozen-lockfile κάνει το CI να σταματά όταν κάτι δεν ταιριάζει, αντί να σερβίρει ένα διαφορετικό build από αυτό που δοκίμασες.
Αξίζει, τρίτον, ως καθρέφτης: σου δείχνει ποιες βιβλιοθήκες χρησιμοποιεί ο κώδικάς σου χωρίς να τις έχει δηλώσει. Όποιος έχει δουλέψει με έργο που έσπασε σε ένα refactor, ξέρει πόσο ακριβή είναι αυτή η γνώση.
Δεν αξίζει τόσο όταν το έργο είναι ένα και μικρό, ή όταν στηρίζεται σε παλιά εργαλεία που περιμένουν επίπεδο node_modules: εκεί το κέρδος σε χώρο είναι μικρό και το κόστος σε --shamefully-hoist και σε δοκιμές μπορεί να το ξεπεράσει. Και δεν είναι εργαλείο για όποιον δεν θέλει να ξέρει τι τραβάει το έργο του — η αυστηρότητά του είναι ακριβώς το αντίθετο της άνεσης.
Τέλος
Ο pnpm είναι ώριμος και πρακτικός. Κρατά ένα αντίγραφο κάθε πακέτου και δίνει σε κάθε έργο έναν σύνδεσμο· δεν σου επιτρέπει να δουλέψεις με βιβλιοθήκες που δεν δήλωσες· και στα μητρώα έχει το βάρος που ταιριάζει σε εργαλείο που χρησιμοποιείται καθημερινά — 37.047 αστέρια, 325 εκατομμύρια λήψεις την εβδομάδα, μία έκδοση που βγήκε πριν πέντε μέρες.
Αν τον δοκιμάσεις με τον τρόπο που τον δοκιμάσαμε εμείς, θα τον κρίνεις σε ένα δεκάλεπτο: ένα έργο, δύο εγκαταστάσεις, δύο φακέλοι, μια ματιά στο μέγεθος και μια στο MODULE_NOT_FOUND. Η διαφορά δεν θα είναι εντύπωση — θα είναι νούμερα, και θα ξέρεις αν σου κάνει.
Πηγές:
Εγκατάσταση
3 ΒΗΜΑΤΑ- npm i -g pnpm
- pnpm add express
- pnpm install
- ΠΗΓΗ
- github.com/pnpm/pnpm