Angular FTP Deployment Setup
How to add the node deploy.js FTP deployment script to another Angular project.
1. Install dependencies
npm install --save-dev ftp-deploy dotenv
2. Add deploy.js to the project root
Create deploy.js next to package.json:
const FtpDeploy = require("ftp-deploy");
const ftpDeploy = new FtpDeploy();
require('dotenv').config();
const config = {
user: process.env.FTP_USER,
password: process.env.FTP_PASSWORD,
host: process.env.FTP_HOST,
port: process.env.FTP_PORT || 21,
localRoot: __dirname + "/dist/<your-app-name>", // <-- update this
remoteRoot: process.env.FTP_REMOTE_ROOT || "/",
include: ["*", "**/*"],
exclude: [],
deleteRemote: false, // set true to wipe remoteRoot before uploading
forcePasv: true,
sftp: false // set true for SFTP instead of FTP
};
console.log("Starting deployment to " + config.host + "...");
ftpDeploy
.deploy(config)
.then(() => console.log("Deployment finished successfully!"))
.catch((err) => {
console.error("Deployment error:", err);
process.exit(1);
});
localRootmust match the Angular build output folder. Checkangular.jsonunderprojects.<name>.architect.build.options.outputPathfor the correct path.
How files are placed on the server
ftp-deploy uploads the contents of localRoot, not the folder itself. The folder name is
stripped and files land directly in remoteRoot:
localRoot: dist/my-app/index.html
remoteRoot: /public_html
→ result: /public_html/index.html (NOT /public_html/my-app/index.html)
Warning: deleteRemote: true
Setting deleteRemote: true deletes every file and subfolder inside remoteRoot before
uploading — including files that have nothing to do with this project (e.g. .htaccess,
subfolders from other apps, etc.). The remoteRoot folder itself is kept, but completely emptied.
There is no selective deletion. If you share remoteRoot with other content, leave
deleteRemote: false and let new uploads overwrite existing files instead.
3. Create .env in the project root
FTP_USER=your_ftp_username
FTP_PASSWORD=your_ftp_password
FTP_HOST=ftp.yourdomain.com
FTP_PORT=21
FTP_REMOTE_ROOT=/public_html
4. Add .env to .gitignore
.env
Never commit .env — it contains plaintext credentials.
5. Add an npm script (optional)
In package.json:
"scripts": {
"deploy": "ng build --configuration production && node deploy.js"
}
Then run:
npm run deploy
Or run the steps separately:
npm run build # produces dist/<your-app-name>
node deploy.js # uploads dist output via FTP
Configuration reference
| Key | Default | Notes |
|---|---|---|
FTP_USER |
— | FTP account username |
FTP_PASSWORD |
— | FTP account password |
FTP_HOST |
— | FTP server hostname or IP |
FTP_PORT |
21 |
Use 22 for SFTP |
FTP_REMOTE_ROOT |
/ |
Remote path to upload into |
localRoot |
(hardcoded) | Must match Angular's outputPath |
deleteRemote |
false |
Set true to delete all contents of remoteRoot before upload — including files unrelated to this project. The folder itself is preserved but fully emptied. Boolean only; no selective deletion available. |
sftp |
false |
Set true and FTP_PORT=22 to use SFTP |
Troubleshooting
- Blank remote folder after deploy — check that
localRootmatches the actual build output directory. Runnpm run buildand confirm the folder exists underdist/. - Connection refused — verify
FTP_HOSTandFTP_PORT. Some hosts require passive mode (forcePasv: true) which is already on by default. - Permission denied — confirm the FTP user has write access to
FTP_REMOTE_ROOT. .envnot loaded — make suredeploy.jsis run from the project root (node deploy.js, notnode path/to/deploy.jsfrom elsewhere).