So I'll comment in this frontend service
and now we can define the configuration
for this frontend service.
Now it's not too difficult.
We can again have a look at the docker run command we used.
And in the end,
the most interesting thing now
is that this also needs interactive mode.
That's something we haven't set up before
for the other containers.
Other than that,
it's just options we already know,
some ports,
then these two options,
which we don't need to add to docker-compose
and one volume.
So in docker-compose.yaml,
here for front-end,
I will start with the image again.
And just as with the backend,
the image should be built.
Because I'm not using a prebuilt image.
I'm not using an image on docker hub.
Instead I'll specify build here
and then point at the frontend folder, in this case,
because it's the frontend folder
which holds the docker file
for this react application image.
So that's the folder we wanna point at
so that this image is built.
As a side note, by the way,
whenever you run docker up again,
it does not always rebuild images, of course,
if an image already exists,
it uses that existing image again.
It only rebuilds if something changed about that image,
if you changed your code, for example,
and it detects that rebuilding is required.
So docker-compose will be pretty smart about that.
But that's just a side note.
So after building this,
we also have some ports here.
And here we wanna publish port 3000
on port 3000 in the host machine.
We also got volumes here
or to be precise one volume,
and that's a bind mount.
And again,
now we don't have to specify this super long absolute path.
Instead, we can specify a relative path.
And here I want to bind
my frontend source folder
to the app source folder
inside of the container.
And this is how we can do it.
This will set up such a bind mount
so that code changes are instantly reflected
in the running container.
And now the only remaining thing is this interactive mode,
which this reactive needs.
How can we specify this?
Well, there are two options for this,
which we can add to our service configuration.
We got the stdin_open option here,
which we can set to true.
To let docker know
that this service needs an open input connection.
And we got the TTY option,
which we should also set to true
because in the end
the -it flag
is just a combination of the dash input flag
for opening standard input.
And the TTY flag for attaching this terminal, so to say.
And with these two options added
the frontend container
will be started in this interactive mode.
Even if you then started in detached mode,
it internally still knows that it's able to receive input
and it will then start up correctly.
We could also add depends_on here
and depend on our backend
to ensure that we only starts the frontend
if the backend started up.
It's up to you if your application needs that or not.
There might be applications which even work,
to a certain extent, if the backend is not up and running
but here we could also add it.
And with all that done,
we again can open a terminal
and run docker-compose up
and start in detached mode.
And now it will build
all the images it needs to build.
It detects that the backend image doesn't need to be built.
So it will not do that.
And it will then also start
all the containers based on all the images
with all the options we specified here
in the docker-compose.yaml file.
So let's wait for this frontend image build process
to finish.
This is looking good,
looks like we're done.
And now with that,
we got three containers up and running
and we should now be able
to visit local host 3000 and see our application.
And we do.
And if I now add a goal here,
that's added and if I reload,
it's still there.
Because it's saved in a database
with help of the backend.
And if I now run docker-compose down,
everything is teared down.
But as I mentioned,
volumes are kept.
So if I restart everything now,
with one command,
this is now super fast
because images don't need to be rebuilt.
I can reload.
And it works just as before.
And my goal is also still there.
Of course deleting all the words though.
And this is now docker-compose,
and it should be fairly obvious
why it is awesome
and why it can be really helpful
in more complex projects.
Instead of running all these individual commands
all the time.
And therefore, having to fiddle around in the terminal.
We have one convenient configuration file,
which is easy to read and manipulate,
easy to maintain and manage.
And then we just have two main commands,
docker-compose up and down
to bring all these connected services up or down
and let Docker do all the other heavy lifting.
And that is pretty, pretty useful,
especially for bigger projects.
And in this demo project
we could already see why Docker Compose
is a great tool.